summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Config14
-rw-r--r--src/Makefile6
-rw-r--r--src/Makefile.housekeeping29
-rw-r--r--src/arch/armnommu/Config6
-rw-r--r--src/arch/armnommu/core/serial.c4
-rw-r--r--src/arch/armnommu/drivers/net/p2001_eth.c365
-rw-r--r--src/arch/armnommu/include/hardware.h17
-rw-r--r--src/arch/armnommu/include/lxt971a.h30
-rw-r--r--src/arch/armnommu/include/stdint.h12
-rw-r--r--src/arch/e1/include/stdint.h12
-rw-r--r--src/arch/i386/Config2
-rw-r--r--src/arch/i386/Makefile6
-rw-r--r--src/arch/i386/core/elf.c2
-rw-r--r--src/arch/i386/core/freebsd_loader.c6
-rw-r--r--src/arch/i386/core/hooks.c10
-rw-r--r--src/arch/i386/core/multiboot_loader.c99
-rw-r--r--src/arch/i386/firmware/pcbios/basemem.c8
-rw-r--r--src/arch/i386/image/nbi.c164
-rw-r--r--src/arch/i386/image/pxe_image.c (renamed from src/arch/i386/core/pxe_loader.c)1
-rw-r--r--src/arch/i386/include/basemem.h2
-rw-r--r--src/arch/i386/include/bochs.h15
-rw-r--r--src/arch/i386/include/hooks.h2
-rw-r--r--src/arch/i386/include/librm.h4
-rw-r--r--src/arch/i386/include/pxe_addr.h17
-rw-r--r--src/arch/i386/include/pxe_callbacks.h10
-rw-r--r--src/arch/i386/include/pxe_types.h35
-rw-r--r--src/arch/i386/include/realmode.h5
-rw-r--r--src/arch/i386/include/registers.h103
-rw-r--r--src/arch/i386/include/stdint.h12
-rw-r--r--src/arch/i386/include/virtaddr.h3
-rw-r--r--src/arch/i386/prefix/hdprefix.S296
-rw-r--r--src/arch/i386/prefix/int19exit.c26
-rw-r--r--src/arch/i386/prefix/romprefix.S6
-rw-r--r--src/arch/i386/prefix/select_isapnp.c6
-rw-r--r--src/arch/i386/prefix/select_pci.c4
-rw-r--r--src/arch/i386/transitions/libkir.S10
-rw-r--r--src/arch/i386/transitions/librm.S34
-rw-r--r--src/arch/i386/transitions/librm_mgmt.c4
-rw-r--r--src/arch/ia64/core/efi.c2
-rw-r--r--src/arch/ia64/include/stdint.h12
-rw-r--r--src/config.h21
-rw-r--r--src/core/background.c47
-rw-r--r--src/core/buffer.c278
-rw-r--r--src/core/config.c3
-rw-r--r--src/core/console.c91
-rw-r--r--src/core/elf_loader.c6
-rw-r--r--src/core/errno.c61
-rw-r--r--src/core/main.c26
-rw-r--r--src/core/nic.c215
-rw-r--r--src/core/pxe_export.c1445
-rw-r--r--src/core/vsprintf.c86
-rw-r--r--src/doc/build_sys.dox419
-rw-r--r--src/doxygen.cfg208
-rw-r--r--src/drivers/bus/isapnp.c254
-rw-r--r--src/drivers/bus/pci.c9
-rw-r--r--src/drivers/net/3c515.c4
-rw-r--r--src/drivers/net/amd8111e.c681
-rw-r--r--src/drivers/net/amd8111e.h629
-rw-r--r--src/drivers/net/davicom.c7
-rw-r--r--src/drivers/net/depca.c7
-rw-r--r--src/drivers/net/dmfe.c7
-rw-r--r--src/drivers/net/e1000.c1076
-rw-r--r--src/drivers/net/eepro.c30
-rw-r--r--src/drivers/net/eepro100.c7
-rw-r--r--src/drivers/net/forcedeth.c811
-rw-r--r--src/drivers/net/mlx_ipoib/MT23108_PRM.h2800
-rw-r--r--src/drivers/net/mlx_ipoib/MT23108_PRM_append.h199
-rw-r--r--src/drivers/net/mlx_ipoib/MT25218_PRM.h3463
-rw-r--r--src/drivers/net/mlx_ipoib/bit_ops.h126
-rw-r--r--src/drivers/net/mlx_ipoib/cmdif.h50
-rw-r--r--src/drivers/net/mlx_ipoib/cmdif_comm.c564
-rw-r--r--src/drivers/net/mlx_ipoib/cmdif_comm.h60
-rw-r--r--src/drivers/net/mlx_ipoib/cmdif_mt23108.c193
-rw-r--r--src/drivers/net/mlx_ipoib/cmdif_mt25218.c457
-rw-r--r--src/drivers/net/mlx_ipoib/cmdif_priv.h50
-rw-r--r--src/drivers/net/mlx_ipoib/doc/README.boot_over_ib176
-rw-r--r--src/drivers/net/mlx_ipoib/ib_driver.c342
-rw-r--r--src/drivers/net/mlx_ipoib/ib_driver.h169
-rw-r--r--src/drivers/net/mlx_ipoib/ib_mad.c396
-rw-r--r--src/drivers/net/mlx_ipoib/ib_mad.h110
-rw-r--r--src/drivers/net/mlx_ipoib/ib_mt23108.c1701
-rw-r--r--src/drivers/net/mlx_ipoib/ib_mt25218.c1929
-rw-r--r--src/drivers/net/mlx_ipoib/ipoib.c1027
-rw-r--r--src/drivers/net/mlx_ipoib/ipoib.h297
-rw-r--r--src/drivers/net/mlx_ipoib/mad_attrib.h244
-rw-r--r--src/drivers/net/mlx_ipoib/mt23108.c245
-rw-r--r--src/drivers/net/mlx_ipoib/mt23108.h543
-rw-r--r--src/drivers/net/mlx_ipoib/mt23108_imp.c230
-rw-r--r--src/drivers/net/mlx_ipoib/mt25218.c245
-rw-r--r--src/drivers/net/mlx_ipoib/mt25218.h546
-rw-r--r--src/drivers/net/mlx_ipoib/mt25218_imp.c230
-rw-r--r--src/drivers/net/mlx_ipoib/mt_version.c23
-rw-r--r--src/drivers/net/mtd80x.c7
-rw-r--r--src/drivers/net/natsemi.c11
-rwxr-xr-xsrc/drivers/net/ns83820.c7
-rw-r--r--src/drivers/net/pcnet32.c7
-rw-r--r--src/drivers/net/r8169.c7
-rw-r--r--src/drivers/net/sis900.c4
-rw-r--r--src/drivers/net/sis900.h7
-rw-r--r--src/drivers/net/smc9000.c449
-rw-r--r--src/drivers/net/smc9000.h114
-rw-r--r--src/drivers/net/sundance.c7
-rw-r--r--src/drivers/net/tg3.c4
-rw-r--r--src/drivers/net/tg3.h2
-rw-r--r--src/drivers/net/tlan.h20
-rw-r--r--src/drivers/net/tulip.c18
-rw-r--r--src/drivers/net/w89c840.c7
-rw-r--r--src/include/background.h52
-rw-r--r--src/include/buffer.h96
-rw-r--r--src/include/compiler.h127
-rw-r--r--src/include/console.h83
-rw-r--r--src/include/dns.h4
-rw-r--r--src/include/errno.h141
-rw-r--r--src/include/etherboot.h59
-rw-r--r--src/include/igmp.h33
-rw-r--r--src/include/nmb.h2
-rw-r--r--src/include/pci_ids.h1
-rw-r--r--src/include/pxe.h956
-rw-r--r--src/include/pxe_api.h1696
-rw-r--r--src/include/pxe_export.h61
-rw-r--r--src/include/pxe_types.h126
-rw-r--r--src/include/tables.h214
-rw-r--r--src/include/tftp.h169
-rw-r--r--src/include/tftpcore.h33
-rw-r--r--src/include/vsprintf.h46
-rw-r--r--src/interface/pxe/pxe.c311
-rw-r--r--src/interface/pxe/pxe_errors.c102
-rw-r--r--src/interface/pxe/pxe_loader.c83
-rw-r--r--src/interface/pxe/pxe_preboot.c249
-rw-r--r--src/interface/pxe/pxe_tftp.c623
-rw-r--r--src/interface/pxe/pxe_udp.c332
-rw-r--r--src/interface/pxe/pxe_undi.c538
-rw-r--r--src/proto/fsp.c245
-rw-r--r--src/proto/http.c15
-rw-r--r--src/proto/igmp.c166
-rw-r--r--src/proto/nfs.c2
-rw-r--r--src/proto/nmb.c7
-rw-r--r--src/proto/tcp.c2
-rw-r--r--src/proto/tftm.c607
-rw-r--r--src/proto/tftp.c282
-rw-r--r--src/proto/tftpcore.c541
-rwxr-xr-xsrc/util/makerom.pl28
142 files changed, 28154 insertions, 4793 deletions
diff --git a/src/Config b/src/Config
index ca069c769..2f3dea846 100644
--- a/src/Config
+++ b/src/Config
@@ -195,6 +195,18 @@
#
# Obscure options you probably don't need to touch:
#
+# -DZPXE_SUFFIX_STRIP
+# If the last 5 characters of the filename passed to Etherboot is
+# ".zpxe" then strip it off. This is useful in cases where a DHCP server
+# is not able to be configured to support conditionals. The way it works
+# is that the DHCP server is configured with a filename like
+# "foo.nbi.zpxe" so that when PXE asks for a filename it gets that, and
+# loads Etherboot from that file. Etherboot then starts up and once
+# again asks the DHCP server for a filename and once again gets
+# foo.nbi.zpxe, but with this option turned on loads "foo.nbi" instead.
+# This allows people to use Etherboot who might not otherwise be able to
+# because their DHCP servers won't let them.
+#
# -DPOWERSAVE
# Halt the processor when waiting for keyboard input
# which saves power while waiting for user interaction.
@@ -295,7 +307,7 @@ CFLAGS+= -DALLOW_ONLY_ENCAPSULATED
# Limit the delay on packet loss/congestion to a more bearable value. See
# description above. If unset, do not limit the delay between resend.
-CFLAGS+= -DBACKOFF_LIMIT=7 -DCONGESTED
+CFLAGS+= -DBACKOFF_LIMIT=5 -DCONGESTED
# More optional features
# CFLAGS+= -DTRY_FLOPPY_FIRST=4
diff --git a/src/Makefile b/src/Makefile
index fa7b3f3f9..cb6b944d3 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -29,7 +29,7 @@ include arch/$(ARCH)/Config
# If invoked with no build target, print out a helpfully suggestive
# message.
#
-noargs : blib
+noargs :
@echo '===================================================='
@echo 'No target specified. To specify a target, do: '
@echo
@@ -79,6 +79,7 @@ MKCONFIG ?= $(PERL) ./util/mkconfig.pl
SYMCHECK ?= $(PERL) ./util/symcheck.pl
SORTOBJDUMP ?= $(PERL) ./util/sortobjdump.pl
NRV2B ?= ./util/nrv2b
+DOXYGEN ?= doxygen
# Location to place generated files
#
@@ -130,10 +131,11 @@ DEBUG_TARGETS += dbg2.o dbg.o c s
#
SRCDIRS += core
SRCDIRS += proto
-SRCDIRS += image
+#SRCDIRS += image
SRCDIRS += drivers/bus
SRCDIRS += drivers/net
#SRCDIRS += drivers/disk
+SRCDIRS += interface/pxe
# NON_AUTO_SRCS lists files that are excluded from the normal
# automatic build system.
diff --git a/src/Makefile.housekeeping b/src/Makefile.housekeeping
index 1f06d698b..2a9503263 100644
--- a/src/Makefile.housekeeping
+++ b/src/Makefile.housekeeping
@@ -10,8 +10,8 @@ CLEANUP := $(BIN)/*.* # *.* to avoid catching the "CVS" directory
# Version number calculations
#
VERSION_MAJOR = 5
-VERSION_MINOR = 3
-VERSION_PATCH = 14
+VERSION_MINOR = 5
+VERSION_PATCH = 0
EXTRAVERSION =
MM_VERSION = $(VERSION_MAJOR).$(VERSION_MINOR)
VERSION = $(MM_VERSION).$(VERSION_PATCH)$(EXTRAVERSION)
@@ -422,6 +422,31 @@ $(BIN)/%.rebuild :
rm -f $(BIN)/$*
$(MAKE) $(MAKEFLAGS) $(BIN)/$*
+# Documentation
+#
+$(BIN)/doxygen.cfg : doxygen.cfg $(MAKEDEPS)
+ $(PERL) -pe 's{\@SRCDIRS\@}{$(SRCDIRS)}; ' \
+ -e 's{\@BIN\@}{$(BIN)}; ' \
+ -e 's{\@ARCH\@}{$(ARCH)}; ' \
+ $< > $@
+
+$(BIN)/doc : $(BIN)/doxygen.cfg
+ $(DOXYGEN) $<
+
+.PHONY : $(BIN)/doc
+
+VERYCLEANUP += $(BIN)/doc
+
+doc : $(BIN)/doc
+
+docview :
+ @[ -f $(BIN)/doc/html/index.html ] || $(MAKE) $(BIN)/doc
+ @if [ -n "$$BROWSER" ] ; then \
+ ( $$BROWSER $(BIN)/doc/html/index.html & ) ; \
+ else \
+ echo "Documentation index in $(BIN)/doc/html/index.html" ; \
+ fi
+
# Clean-up
#
clean :
diff --git a/src/arch/armnommu/Config b/src/arch/armnommu/Config
index 4c220cd50..579420388 100644
--- a/src/arch/armnommu/Config
+++ b/src/arch/armnommu/Config
@@ -17,6 +17,12 @@ CFLAGS+= -DRAWADDR=0x40100000
# NIC Debug Outputs
#CFLAGS+= -DDEBUG_NIC
+# Reduced Media Independent Interface
+# MAZBR LPEC2001: MII (Intel LXT971ALE at 0..1)
+# Elmeg D@VOS : RMII (Altima AC104-QF at 4..7)
+# Telekom XI521 : RMII (Altima AC104-QF at 4..7)
+#CFLAGS+= -DRMII
+
# Fixed MAC address
# p2001_eth has no flash and fixed mac address
#CFLAGS+= -DMAC_HW_ADDR_DRV="'H','Y','L','N','X','1'"
diff --git a/src/arch/armnommu/core/serial.c b/src/arch/armnommu/core/serial.c
index 3ae98d47a..0fb6e79b9 100644
--- a/src/arch/armnommu/core/serial.c
+++ b/src/arch/armnommu/core/serial.c
@@ -17,7 +17,7 @@ void serial_putc(int ch)
{
/* wait for room in the 32 byte tx FIFO */
while ((P2001_UART->r.STATUS & 0x3f) > /* 30 */ 0) ;
- P2001_UART->w.TX1 = ch & 0xff;
+ P2001_UART->w.TX[0] = ch & 0xff;
}
/*
@@ -27,7 +27,7 @@ void serial_putc(int ch)
int serial_getc(void)
{
while (((P2001_UART->r.STATUS >> 6) & 0x3f) == 0) ;
- return P2001_UART->r.RX1 & 0xff;
+ return P2001_UART->r.RX[0] & 0xff;
}
/*
diff --git a/src/arch/armnommu/drivers/net/p2001_eth.c b/src/arch/armnommu/drivers/net/p2001_eth.c
index 81bc84c3c..bdf2f0e96 100644
--- a/src/arch/armnommu/drivers/net/p2001_eth.c
+++ b/src/arch/armnommu/drivers/net/p2001_eth.c
@@ -1,10 +1,10 @@
/**************************************************************************
-Etherboot - BOOTP/TFTP Bootstrap Program
-P2001 NIC driver for Etherboot
-***************************************************************************/
+ * Etherboot - BOOTP/TFTP Bootstrap Program
+ * P2001 NIC driver for Etherboot
+ **************************************************************************/
/*
- * Copyright (C) 2004 Tobias Lorenz
+ * Copyright (C) 2005 Tobias Lorenz
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -19,7 +19,7 @@ P2001 NIC driver for Etherboot
#include "isa.h"
#include "hardware.h"
-#include "lxt971a.h"
+#include "mii.h"
#include "timer.h"
@@ -31,25 +31,20 @@ static unsigned char MAC_HW_ADDR[6]={MAC_HW_ADDR_DRV};
#define DMA_BUF_SIZE 2048 /* Buffer size */
static DMA_DSC txd __attribute__ ((__section__(".dma.desc")));
static DMA_DSC rxd[NUM_RX_DESC] __attribute__ ((__section__(".dma.desc")));
-static unsigned char rxb[NUM_RX_DESC * DMA_BUF_SIZE] __attribute__ ((__section__(".dma.buffer")));
-static unsigned char txb[ DMA_BUF_SIZE] __attribute__ ((__section__(".dma.buffer")));
+static char rxb[NUM_RX_DESC * DMA_BUF_SIZE] __attribute__ ((__section__(".dma.buffer")));
+static char txb[ DMA_BUF_SIZE] __attribute__ ((__section__(".dma.buffer")));
static unsigned int cur_rx;
/* Device selectors */
static unsigned int cur_channel; // DMA channel : 0..3
static unsigned int cur_phy; // PHY Address : 0..31
static P2001_ETH_regs_ptr EU; // Ethernet Unit : 0x0018_000 with _=0..3
-static P2001_ETH_regs_ptr MU; // Management Unit: 0x00180000
-#define MDIO_MAXCOUNT 1000 /* mdio abort */
-static unsigned int mdio_error; /* mdio error */
-
-/* Function prototypes */
-static void p2001_eth_mdio_init ();
-static void p2001_eth_mdio_write(unsigned int phyadr, unsigned int regadr, unsigned int data);
-static unsigned int p2001_eth_mdio_read (unsigned int phyadr, unsigned int regadr);
-extern unsigned int p2001_eth_mdio_error;
+/* mdio handling */
+static int p2001_eth_mdio_read (int phy_id, int location);
+static void p2001_eth_mdio_write(int phy_id, int location, int val);
+/* net_device functions */
static int p2001_eth_poll (struct nic *nic, int retrieve);
static void p2001_eth_transmit (struct nic *nic, const char *d,
unsigned int t, unsigned int s, const char *p);
@@ -60,103 +55,107 @@ static void p2001_eth_init ();
static void p2001_eth_disable (struct dev *dev);
static int p2001_eth_check_link(unsigned int phy);
+static int link;
+static void p2001_eth_phyreset ();
static int p2001_eth_probe (struct dev *dev, unsigned short *probe_addrs __unused);
+/* Supported MII list */
+static struct mii_chip_info {
+ const char * name;
+ unsigned int physid; // (MII_PHYSID2 << 16) | MII_PHYSID1
+} mii_chip_table[] = {
+ { "Intel LXT971A", 0x78e20013 },
+ { "Altima AC104-QF", 0x55410022 },
+ {NULL,0},
+};
+
+
/**************************************************************************
-PHY MANAGEMENT UNIT - Read/write
-***************************************************************************/
-static void p2001_eth_mdio_init()
+ * PHY MANAGEMENT UNIT - Read/write
+ **************************************************************************/
+
+/**
+ * mdio_read - read MII PHY register
+ * @dev: the net device to read
+ * @regadr: the phy register id to read
+ *
+ * Read MII registers through MDIO and MDC
+ * using MDIO management frame structure and protocol(defined by ISO/IEC).
+ */
+static int p2001_eth_mdio_read(int phy_id, int location)
{
- /* reset ethernet PHYs */
- printf("Resetting PHYs...\n");
+ int result, boguscnt = 1000;
- /* GPIO24/25: TX_ER2/TX_ER0 */
- /* GPIO26/27: PHY_RESET/TX_ER1 */
- P2001_GPIO->PIN_MUX |= 0x0018;
- // 31-16: 0000 1111 0000 0000
- P2001_GPIO->GPIO2_En |= 0x0400;
+ do {
+ /* Warten bis Hardware inaktiv (MIU = "0") */
+ while (P2001_MU->MU_CNTL & 0x8000)
+ barrier();
- P2001_GPIO->GPIO2_Out |= 0x04000000;
- P2001_GPIO->GPIO2_Out &= ~0x0400;
- mdelay(500);
- P2001_GPIO->GPIO2_Out |= 0x0400;
+ /* Schreiben MU_CNTL */
+ P2001_MU->MU_CNTL = location + (phy_id<<5) + (2<<10);
- /* set management unit clock divisor */
- // max. MDIO CLK = 2.048 MHz (EU.doc)
- // max. MDIO CLK = 8.000 MHz (LXT971A)
- // sysclk/(2*(n+1)) = MDIO CLK <= 2.048 MHz
- // n >= sysclk/4.096 MHz - 1
-#if SYSCLK == 73728000
- P2001_MU->MU_DIV = 17; // 73.728 MHZ =17=> 2.020 MHz
-#else
- //MU->MU_DIV = (SYSCLK/4.096)-1;
-#error "Please define a proper MDIO CLK divisor for that sysclk."
-#endif
- asm("nop \n nop");
+ /* Warten bis Hardware aktiv (MIU = "1") */
+ while ((P2001_MU->MU_CNTL & 0x8000) == 0)
+ barrier();
+ //asm("nop \r\n nop");
+
+ /* Warten bis Hardware inaktiv (MIU = "0") */
+ while (P2001_MU->MU_CNTL & 0x8000)
+ barrier();
+
+ /* Fehler, wenn MDIO Read Error (MRE = "1") */
+ } while ((P2001_MU->MU_CNTL & 0x4000) && (--boguscnt > 0));
+
+ /* Lesen MU_DATA */
+ result = P2001_MU->MU_DATA;
+
+ if (boguscnt == 0)
+ return 0;
+ if ((result & 0xffff) == 0xffff)
+ return 0;
+
+ return result & 0xffff;
}
-static void p2001_eth_mdio_write(unsigned int phyadr, unsigned int regadr, unsigned int data)
-{
- static unsigned int count;
- count = 0;
+/**
+ * mdio_write - write MII PHY register
+ * @dev: the net device to write
+ * @regadr: the phy register id to write
+ * @value: the register value to write with
+ *
+ * Write MII registers with @value through MDIO and MDC
+ * using MDIO management frame structure and protocol(defined by ISO/IEC)
+ */
+static void p2001_eth_mdio_write(int phy_id, int location, int val)
+{
/* Warten bis Hardware inaktiv (MIU = "0") */
- while ((MU->MU_CNTL & 0x8000) && (count < MDIO_MAXCOUNT))
- count++;
+ while (P2001_MU->MU_CNTL & 0x8000)
+ barrier();
/* Schreiben MU_DATA */
- MU->MU_DATA = data;
+ P2001_MU->MU_DATA = val;
/* Schreiben MU_CNTL */
- MU->MU_CNTL = regadr + (phyadr<<5) + (1<<10);
+ P2001_MU->MU_CNTL = location + (phy_id<<5) + (1<<10);
/* Warten bis Hardware aktiv (MIU = "1") */
- while (((MU->MU_CNTL & 0x8000) == 0) && (count < MDIO_MAXCOUNT))
- count++;
+ while ((P2001_MU->MU_CNTL & 0x8000) == 0)
+ barrier();
//asm("nop \r\n nop");
/* Warten bis Hardware inaktiv (MIU = "0") */
- while ((MU->MU_CNTL & 0x8000) && (count < MDIO_MAXCOUNT))
- count++;
-
- mdio_error = (count >= MDIO_MAXCOUNT);
+ while (P2001_MU->MU_CNTL & 0x8000)
+ barrier();
}
-static unsigned int p2001_eth_mdio_read(unsigned int phyadr, unsigned int regadr)
-{
- static unsigned int count;
- count = 0;
-
- do {
- /* Warten bis Hardware inaktiv (MIU = "0") */
- while ((MU->MU_CNTL & 0x8000) && (count < MDIO_MAXCOUNT))
- count++;
-
- /* Schreiben MU_CNTL */
- MU->MU_CNTL = regadr + (phyadr<<5) + (2<<10);
-
- /* Warten bis Hardware aktiv (MIU = "1") */
- while (((MU->MU_CNTL & 0x8000) == 0) && (count < MDIO_MAXCOUNT))
- count++;
- //asm("nop \r\n nop");
-
- /* Warten bis Hardware inaktiv (MIU = "0") */
- while ((MU->MU_CNTL & 0x8000) && (count < MDIO_MAXCOUNT))
- count++;
-
- /* Fehler, wenn MDIO Read Error (MRE = "1") */
- } while ((MU->MU_CNTL & 0x4000) && (count < MDIO_MAXCOUNT));
-
- /* Lesen MU_DATA */
- mdio_error = (count >= MDIO_MAXCOUNT);
- return MU->MU_DATA;
-}
/**************************************************************************
-POLL - Wait for a frame
-***************************************************************************/
+ * POLL - Wait for a frame
+ **************************************************************************/
+
/* Function: p2001_eth_poll
*
* Description: checks for a received packet and returns it if found.
@@ -231,9 +230,11 @@ static int p2001_eth_poll(struct nic *nic, int retrieve)
}
+
/**************************************************************************
-TRANSMIT - Transmit a frame
-***************************************************************************/
+ * TRANSMIT - Transmit a frame
+ **************************************************************************/
+
/* Function: p2001_eth_transmit
*
* Description: transmits a packet and waits for completion or timeout.
@@ -271,7 +272,7 @@ static void p2001_eth_transmit(
// TMAC_CNTL.ATP does the same
#ifdef DEBUG_NIC
- printf("p2001_eth_transmit: packet from %! to %! sent\n", txb+ETH_ALEN, txb);
+ printf("p2001_eth_transmit: packet from %! to %! sent (size: %d)\n", txb+ETH_ALEN, txb, s);
#endif
/* configure descriptor */
@@ -281,12 +282,12 @@ static void p2001_eth_transmit(
/* restart the transmitter */
EU->TMAC_DMA_EN = 0x01; /* set run bit */
- while(EU->TMAC_DMA_EN & 0x01) ; /* wait */
+ while(EU->TMAC_DMA_EN & 0x01); /* wait */
#ifdef DEBUG_NIC
/* check status */
status = EU->TMAC_DMA_STAT;
- if (status & ~(0x40))
+ if (status & ~(0x40)) // not END
printf("p2001_eth_transmit: dma status=0x%hx\n", status);
printf("TMAC_MIB6..7: %d:%d\n", EU->TMAC_MIB6, EU->TMAC_MIB7);
@@ -294,9 +295,11 @@ static void p2001_eth_transmit(
}
+
/**************************************************************************
-IRQ - Enable, Disable or Force Interrupts
-***************************************************************************/
+ * IRQ - Enable, Disable or Force Interrupts
+ **************************************************************************/
+
/* Function: p2001_eth_irq
*
* Description: Enable, Disable, or Force, interrupts
@@ -321,9 +324,11 @@ p2001_eth_irq(struct nic *nic __unused, irq_action_t action __unused)
}
+
/**************************************************************************
-INIT - Initialize device
-***************************************************************************/
+ * INIT - Initialize device
+ **************************************************************************/
+
/* Function: p2001_init
*
* Description: resets the ethernet controller chip and various
@@ -335,6 +340,23 @@ static void p2001_eth_init()
{
static int i;
+ /* activate MII 3 */
+ if (cur_channel == 3)
+ P2001_GPIO->PIN_MUX |= (1<<8); // MII_3_en = 1
+
+#ifdef RMII
+ /* RMII init sequence */
+ if (link & LPA_100) {
+ EU->CONF_RMII = (1<<2) | (1<<1); // softres | 100Mbit
+ EU->CONF_RMII = (1<<2) | (1<<1) | (1<<0); // softres | 100Mbit | RMII
+ EU->CONF_RMII = (1<<1) | (1<<0); // 100 Mbit | RMII
+ } else {
+ EU->CONF_RMII = (1<<2); // softres
+ EU->CONF_RMII = (1<<2) | (1<<0); // softres | RMII
+ EU->CONF_RMII = (1<<0); // RMII
+ }
+#endif
+
/* disable transceiver */
// EU->TMAC_DMA_EN = 0; /* clear run bit */
// EU->RMAC_DMA_EN = 0; /* clear run bit */
@@ -353,7 +375,7 @@ static void p2001_eth_init()
// txd.stat = (1<<31) | (1<<30) | (1<<29); // DSC0 OWN|START|END
// txd.cntl = cur_channel << 16; // DSC1 CHANNEL
// txd.cntl |= DMA_BUF_SIZE; // DSC1 LEN
- txd.buf = &txb; // DSC2 BUFFER
+ txd.buf = (char *)&txb; // DSC2 BUFFER
txd.next = &txd; // DSC3 NEXTDSC @self
EU->TMAC_DMA_DESC = &txd;
@@ -371,9 +393,12 @@ static void p2001_eth_init()
EU->RMAC_DMA_DESC = &rxd[0];
/* set transmitter mode */
- EU->TMAC_CNTL = (1<<4) | /* COI: Collision ignore */
- //(1<<3) | /* CSI: Carrier Sense ignore */
- (1<<2); /* ATP: Automatic Transmit Padding */
+ if (link & LPA_DUPLEX)
+ EU->TMAC_CNTL = (1<<4) | /* COI: Collision ignore */
+ (1<<3) | /* CSI: Carrier Sense ignore */
+ (1<<2); /* ATP: Automatic Transmit Padding */
+ else
+ EU->TMAC_CNTL = (1<<2); /* ATP: Automatic Transmit Padding */
/* set receive mode */
EU->RMAC_CNTL = (1<<3) | /* BROAD: Broadcast packets */
@@ -384,9 +409,10 @@ static void p2001_eth_init()
}
+
/**************************************************************************
-DISABLE - Turn off ethernet interface
-***************************************************************************/
+ * DISABLE - Turn off ethernet interface
+ **************************************************************************/
static void p2001_eth_disable(struct dev *dev __unused)
{
/* put the card in its initial state */
@@ -408,40 +434,52 @@ static void p2001_eth_disable(struct dev *dev __unused)
}
+
/**************************************************************************
-LINK - Check for valid link
-***************************************************************************/
+ * LINK - Check for valid link
+ **************************************************************************/
static int p2001_eth_check_link(unsigned int phy)
{
static int status;
- static unsigned int count;
- count = 0;
+ static unsigned int i, physid;
+
+ /* print some information about out PHY */
+ physid = (p2001_eth_mdio_read(phy, MII_PHYSID2) << 16) |
+ p2001_eth_mdio_read(phy, MII_PHYSID1);
+ printf("PHY %d, ID 0x%x ", phy, physid);
+ for (i = 0; mii_chip_table[i].physid; i++)
+ if (mii_chip_table[i].physid == physid) {
+ printf("(%s).\n", mii_chip_table[i].name);
+ break;
+ }
+ if (!mii_chip_table[i].physid)
+ printf("(unknown).\n");
/* Use 0x3300 for restarting NWay */
printf("Starting auto-negotiation... ");
- p2001_eth_mdio_write(phy, Adr_LXT971A_Control, 0x3300);
- if (mdio_error)
- goto failed;
+ p2001_eth_mdio_write(phy, MII_BMCR, 0x3300);
- /* Bits 1.5 and 17.7 are set to 1 once the Auto-Negotiation process to completed. */
+ /* Bit 1.5 is set once the Auto-Negotiation process is completed. */
+ i = 0;
do {
mdelay(500);
- status = p2001_eth_mdio_read(phy, Adr_LXT971A_Status1);
- if (mdio_error || (count++ > 6)) // 6*500ms = 3s timeout
+ status = p2001_eth_mdio_read(phy, MII_BMSR);
+ if (!status || (i++ > 6)) // 6*500ms = 3s timeout
goto failed;
- } while (!(status & 0x20));
-
- /* Bits 1.2 and 17.10 are set to 1 once the link is established. */
- if (p2001_eth_mdio_read(phy, Adr_LXT971A_Status1) & 0x04) {
- /* Bits 17.14 and 17.9 can be used to determine the link operation conditions (speed and duplex). */
- printf("Valid link, operating at: %sMb-%s\n",
- (p2001_eth_mdio_read(phy, Adr_LXT971A_Status2) & 0x4000) ? "100" : "10",
- (p2001_eth_mdio_read(phy, Adr_LXT971A_Status2) & 0x0200) ? "FD" : "HD");
- return 1;
+ } while (!(status & BMSR_ANEGCOMPLETE));
+
+ /* Bits 1.2 is set once the link is established. */
+ if ((status = p2001_eth_mdio_read(phy, MII_BMSR)) & BMSR_LSTATUS) {
+ link = p2001_eth_mdio_read(phy, MII_ADVERTISE) &
+ p2001_eth_mdio_read(phy, MII_LPA);
+ printf(" Valid link, operating at: %sMb-%s\n",
+ (link & LPA_100) ? "100" : "10",
+ (link & LPA_DUPLEX) ? "FD" : "HD");
+ return 1;
}
failed:
- if (mdio_error)
+ if (!status)
printf("Failed\n");
else
printf("No valid link\n");
@@ -449,49 +487,79 @@ failed:
}
+
+/**************************************************************************
+ * PHYRESET - hardware reset all MII PHYs
+ **************************************************************************/
+
+/**
+ * p2001_eth_phyreset - hardware reset all MII PHYs
+ */
+static void p2001_eth_phyreset()
+{
+ /* GPIO24/25: TX_ER2/TX_ER0 */
+ /* GPIO26/27: PHY_RESET/TX_ER1 */
+ P2001_GPIO->PIN_MUX |= 0x0018;
+ // 31-16: 0000 1111 0000 0000
+ P2001_GPIO->GPIO2_En |= 0x0400;
+
+ P2001_GPIO->GPIO2_Out |= 0x04000000;
+ P2001_GPIO->GPIO2_Out &= ~0x0400;
+ mdelay(500);
+ P2001_GPIO->GPIO2_Out |= 0x0400;
+
+#ifdef RMII
+ /* RMII_clk_sel = 0xxb no RMII (default) */
+ /* RMII_clk_sel = 100b COL_0 */
+ /* RMII_clk_sel = 101b COL_1 */
+ /* RMII_clk_sel = 110b COL_2 */
+ /* RMII_clk_sel = 111b COL_3 */
+ P2001_GPIO->PIN_MUX |= (4 << 13);
+#endif
+}
+
+
+
/**************************************************************************
-PROBE - Look for an adapter, this routine's visible to the outside
-***************************************************************************/
+ * PROBE - Look for an adapter, this routine's visible to the outside
+ **************************************************************************/
+
static int p2001_eth_probe(struct dev *dev, unsigned short *probe_addrs __unused)
{
struct nic *nic = (struct nic *)dev;
/* if probe_addrs is 0, then routine can use a hardwired default */
- static int board_found;
- static int valid_link;
/* reset phys and configure mdio clk */
- p2001_eth_mdio_init();
+ printf("Resetting PHYs...\n");
+ p2001_eth_phyreset();
+
+ /* set management unit clock divisor */
+ // max. MDIO CLK = 2.048 MHz (EU.doc)
+ P2001_MU->MU_DIV = (SYSCLK/4096000)-1; // 2.048 MHz
+ //asm("nop \n nop");
/* find the correct PHY/DMA/MAC combination */
- MU = P2001_MU; // MU for all PHYs is only in EU0
printf("Searching for P2001 NICs...\n");
+ cur_phy = -1;
for (cur_channel=0; cur_channel<4; cur_channel++) {
- switch(cur_channel) {
- case 0:
- EU = P2001_EU0;
- cur_phy = 0;
- break;
- case 1:
- EU = P2001_EU1;
- cur_phy = 1;
- break;
- case 2:
- EU = P2001_EU2;
- cur_phy = 2;
- break;
- case 3:
- EU = P2001_EU3;
- cur_phy = 3;
+ EU = P2001_EU(cur_channel);
+
+ /* find next phy */
+ while (++cur_phy < 16) {
+ //printf("phy detect %d\n", cur_phy);
+ if (p2001_eth_mdio_read(cur_phy, MII_BMSR) != 0)
break;
}
+ if (cur_phy == 16) {
+ printf("no more MII PHYs found\n");
+ break;
+ }
/* first a non destructive test for initial value RMAC_TLEN=1518 */
- board_found = (EU->RMAC_TLEN == 1518);
- if (board_found) {
+ if (EU->RMAC_TLEN == 1518) {
printf("Checking EU%d...\n", cur_channel);
- valid_link = p2001_eth_check_link(cur_phy);
- if (valid_link) {
+ if (p2001_eth_check_link(cur_phy)) {
/* initialize device */
p2001_eth_init(nic);
@@ -507,7 +575,6 @@ static int p2001_eth_probe(struct dev *dev, unsigned short *probe_addrs __unused
/* Report the ISA pnp id of the board */
dev->devid.vendor_id = htons(GENERIC_ISAPNP_VENDOR);
- dev->devid.vendor_id = htons(0x1234);
return 1;
}
}
diff --git a/src/arch/armnommu/include/hardware.h b/src/arch/armnommu/include/hardware.h
index 203b78b73..49264d63b 100644
--- a/src/arch/armnommu/include/hardware.h
+++ b/src/arch/armnommu/include/hardware.h
@@ -100,10 +100,7 @@ typedef struct { // 0x00130000U
typedef union { // 0x00140000U
struct { // write
- volatile unsigned int TX1; // 0x00000000U
- volatile unsigned int TX2; // 0x00000004U
- volatile unsigned int TX3; // 0x00000008U
- volatile unsigned int TX4; // 0x0000000CU
+ volatile unsigned int TX[4]; // 0x00000000-0x000CU
volatile unsigned int Baudrate; // 0x00000010U
volatile unsigned int reserved1[0x3];
volatile unsigned int Config; // 0x00000020U
@@ -113,10 +110,7 @@ typedef union { // 0x00140000U
} w; // write
struct { // read
- volatile unsigned int RX1; // 0x00000000U
- volatile unsigned int RX2; // 0x00000004U
- volatile unsigned int RX3; // 0x00000008U
- volatile unsigned int RX4; // 0x0000000CU
+ volatile unsigned int RX[4]; // 0x00000000-0x000CU
volatile unsigned int reserved1[0x4];
volatile unsigned int PRE_STATUS; // 0x00000020U
volatile unsigned int STATUS; // 0x00000024U
@@ -168,11 +162,8 @@ typedef struct { // 0x0018_000U _=0,1,2,3
volatile unsigned int TMAC_DMA_DATA; // 0x00000FF8U
volatile unsigned int TMAC_DMA_ADR; // 0x00000FFCU
} *P2001_ETH_regs_ptr;
-#define P2001_EU0 ((volatile P2001_ETH_regs_ptr) 0x00180000)
-#define P2001_EU1 ((volatile P2001_ETH_regs_ptr) 0x00181000)
-#define P2001_EU2 ((volatile P2001_ETH_regs_ptr) 0x00182000)
-#define P2001_EU3 ((volatile P2001_ETH_regs_ptr) 0x00183000)
-#define P2001_MU P2001_EU0
+#define P2001_EU(x) ((volatile P2001_ETH_regs_ptr) ((unsigned int) 0x00180000UL+(0x1000UL*(x)))) /* x = 0..3 */
+#define P2001_MU P2001_EU(0)
#endif
diff --git a/src/arch/armnommu/include/lxt971a.h b/src/arch/armnommu/include/lxt971a.h
deleted file mode 100644
index 16314ec25..000000000
--- a/src/arch/armnommu/include/lxt971a.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2004 Tobias Lorenz
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-/*
- * Intel LXT971ALE (MII-compatible PHY)
- */
-
-#define Adr_LXT971A_Control 0 /* Control Register */
-#define Adr_LXT971A_Status1 1 /* MII Status Register #1 */
-#define Adr_LXT971A_PHY_ID1 2 /* PHY Identification Register 1 */
-#define Adr_LXT971A_PHY_ID2 3 /* PHY Identification Register 2 */
-#define Adr_LXT971A_AN_Advertise 4 /* Auto Negotiation Advertisement Register */
-#define Adr_LXT971A_AN_Link_Ability 5 /* Auto Negotiation Link Partner Base Page Ability Register */
-#define Adr_LXT971A_AN_Expansion 6 /* Auto Negotiation Expansion */
-#define Adr_LXT971A_AN_Next_Page_Txmit 7 /* Auto Negotiation Next Page Transmit Register */
-#define Adr_LXT971A_AN_Link_Next_Page 8 /* Auto Negotiation Link Partner Next Page Receive Register */
-#define Adr_LXT971A_Fast_Control 9 /* Not Implemented */
-#define Adr_LXT971A_Fast_Status 10 /* Not Implemented */
-#define Adr_LXT971A_Extended_Status 15 /* Not Implemented */
-#define Adr_LXT971A_Port_Config 16 /* Configuration Register */
-#define Adr_LXT971A_Status2 17 /* Status Register #2 */
-#define Adr_LXT971A_Interrupt_Enable 18 /* Interrupt Enable Register */
-#define Adr_LXT971A_Interrupt_Status 19 /* Interrupt Status Register */
-#define Adr_LXT971A_LED_Config 20 /* LED Configuration Register */
-#define Adr_LXT971A_Transmit_Control 30 /* Transmit Control Register */
diff --git a/src/arch/armnommu/include/stdint.h b/src/arch/armnommu/include/stdint.h
index 3f5dc3f96..1cb008515 100644
--- a/src/arch/armnommu/include/stdint.h
+++ b/src/arch/armnommu/include/stdint.h
@@ -20,4 +20,16 @@ typedef signed short int16_t;
typedef signed int int32_t;
typedef signed long long int64_t;
+typedef signed char s8;
+typedef unsigned char u8;
+
+typedef signed short s16;
+typedef unsigned short u16;
+
+typedef signed long s32;
+typedef unsigned int u32;
+
+typedef signed long long s64;
+typedef unsigned long long u64;
+
#endif /* STDINT_H */
diff --git a/src/arch/e1/include/stdint.h b/src/arch/e1/include/stdint.h
index 8a7ad978a..505cc3751 100644
--- a/src/arch/e1/include/stdint.h
+++ b/src/arch/e1/include/stdint.h
@@ -13,4 +13,16 @@ typedef signed short int16_t;
typedef signed int int32_t;
typedef signed long long int64_t;
+typedef signed char s8;
+typedef unsigned char u8;
+
+typedef signed short s16;
+typedef unsigned short u16;
+
+typedef signed long s32;
+typedef unsigned int u32;
+
+typedef signed long long s64;
+typedef unsigned long long u64;
+
#endif /* STDINT_H */
diff --git a/src/arch/i386/Config b/src/arch/i386/Config
index db80b38e3..03836c8b5 100644
--- a/src/arch/i386/Config
+++ b/src/arch/i386/Config
@@ -133,7 +133,7 @@ CFLAGS+= -falign-jumps=1 -falign-loops=1 -falign-functions=1
endif
GCC_MINORVERSION = $(word 2, $(GCC_VERSION))
ifneq ($(GCC_MINORVERSION),4)
-CFLAGS+= -mcpu=i386
+CFLAGS+= -march=i386
endif
LDFLAGS+= -N
diff --git a/src/arch/i386/Makefile b/src/arch/i386/Makefile
index 9f207ea0a..94b85c807 100644
--- a/src/arch/i386/Makefile
+++ b/src/arch/i386/Makefile
@@ -1,7 +1,7 @@
# i386-specific directories containing source files
#
SRCDIRS += arch/i386/core arch/i386/transitions arch/i386/prefix
-SRCDIRS += arch/i386/firmware/pcbios arch/i386/firmware/linuxbios
+SRCDIRS += arch/i386/firmware/pcbios
SRCDIRS += arch/i386/image
SRCDIRS += arch/i386/drivers/bus
SRCDIRS += arch/i386/drivers/net
@@ -82,6 +82,10 @@ MEDIA += dsk
OBJS_dskprefix = dskprefix zdskprefix
CFLAGS_zdskprefix = $(CFLAGS_ZPREFIX)
+MEDIA += hd
+OBJS_hdprefix = hdprefix zhdprefix
+CFLAGS_zhdprefix = $(CFLAGS_ZPREFIX)
+
MEDIA += raw
OBJS_rawprefix = rawprefix zrawprefix
CFLAGS_zrawprefix = $(CFLAGS_ZPREFIX)
diff --git a/src/arch/i386/core/elf.c b/src/arch/i386/core/elf.c
index 40a18a1f0..fbb4032f3 100644
--- a/src/arch/i386/core/elf.c
+++ b/src/arch/i386/core/elf.c
@@ -74,7 +74,7 @@ struct Elf_Bhdr *prepare_boot_params(void *header)
notes.nf1.n_descsz = sizeof(notes.nf1_bootp_data);
notes.nf1.n_type = EB_BOOTP_DATA;
CP(notes.nf1_name, EB_PARAM_NOTE);
- notes.nf1_bootp_data = virt_to_phys(BOOTP_DATA_ADDR);
+ notes.nf1_bootp_data = virt_to_phys(&bootp_data);
notes.nf2.n_namesz = sizeof(EB_PARAM_NOTE);
notes.nf2.n_descsz = sizeof(notes.nf2_header);
diff --git a/src/arch/i386/core/freebsd_loader.c b/src/arch/i386/core/freebsd_loader.c
index 4e820e8e9..464f6d939 100644
--- a/src/arch/i386/core/freebsd_loader.c
+++ b/src/arch/i386/core/freebsd_loader.c
@@ -216,7 +216,7 @@ static int elf_freebsd_debug_loader(unsigned int offset)
estate.toread, estate.curaddr);
#endif
/* Save where we are loading this... */
- symtab_load = phys_to_virt(estate.curaddr);
+ symtab_load = estate.curaddr;
*((long *)phys_to_virt(estate.curaddr)) = estate.toread;
estate.curaddr += sizeof(long);
@@ -244,7 +244,7 @@ static int elf_freebsd_debug_loader(unsigned int offset)
estate.toread, estate.curaddr);
#endif
/* Save where we are loading this... */
- symstr_load = phys_to_virt(estate.curaddr);
+ symstr_load = estate.curaddr;
*((long *)phys_to_virt(estate.curaddr)) = estate.toread;
estate.curaddr += sizeof(long);
@@ -290,7 +290,7 @@ static void elf_freebsd_boot(unsigned long entry)
/* Assumes size of long is a power of 2... */
bsdinfo.bi_esymtab = (symstr_load +
sizeof(long) +
- *((long *)symstr_load) +
+ *((long *)phys_to_virt(symstr_load)) +
sizeof(long) - 1) & ~(sizeof(long) - 1);
/* Where we will build the meta data... */
diff --git a/src/arch/i386/core/hooks.c b/src/arch/i386/core/hooks.c
index b2c82a1e2..313dc6181 100644
--- a/src/arch/i386/core/hooks.c
+++ b/src/arch/i386/core/hooks.c
@@ -13,20 +13,20 @@
* the prefix requested.
*
*/
-void arch_main ( struct i386_all_regs *regs ) {
- void (*exit_path) ( struct i386_all_regs *regs );
+void arch_main ( struct i386_all_regs *ix86 ) {
+ void (*exit_path) ( struct i386_all_regs *ix86 );
/* Determine exit path requested by prefix */
- exit_path = ( typeof ( exit_path ) ) regs->eax;
+ exit_path = ( typeof ( exit_path ) ) ix86->regs.eax;
/* Call to main() */
- regs->eax = main();
+ ix86->regs.eax = main();
if ( exit_path ) {
/* Prefix requested that we use a particular function
* as the exit path, so we call this function, which
* must not return.
*/
- exit_path ( regs );
+ exit_path ( ix86 );
}
}
diff --git a/src/arch/i386/core/multiboot_loader.c b/src/arch/i386/core/multiboot_loader.c
index e9785f1c9..562252427 100644
--- a/src/arch/i386/core/multiboot_loader.c
+++ b/src/arch/i386/core/multiboot_loader.c
@@ -56,28 +56,82 @@ struct multiboot_header {
};
static struct multiboot_header *mbheader;
+static unsigned int mbimgoffset, mboffset;
+static unsigned char mbbuffer[12];
static struct multiboot_info mbinfo;
-static void multiboot_probe(unsigned char *data, int len)
+static void multiboot_init(void)
+{
+ mbheader = NULL;
+ mbimgoffset = 0;
+ mboffset = 0;
+}
+
+/* Remember this probing function is actually different from the usual probing
+ * functions, since the Multiboot header is somewhere in the first 8KB of the
+ * image and it is byte aligned, but there is not much more known about how to
+ * find it. In the Etherboot context the most complicated issue is that the
+ * image has to be processed block-by-block, with unknown block size and no
+ * guarantees about block alignment with respect to the image. */
+static void multiboot_peek(unsigned char *data, int len)
{
- int offset;
struct multiboot_header *h;
- /* Multiboot spec requires the header to be in first 8KB of the image */
- if (len > 8192)
- len = 8192;
+ /* If we have already searched the first 8KB of the image or if we have
+ * already found a valid Multiboot header, skip this code. */
+ if ((mboffset == 12) || (mbimgoffset >= 8192))
+ return;
+
+ if (mbimgoffset + len >= 8192)
+ len = 8192 - mbimgoffset;
- for (offset = 0; offset < len; offset += 4) {
- h = (struct multiboot_header *) (data + offset);
- if (h->magic == MULTIBOOT_HEADER_MAGIC
- && h->magic + h->flags + h->checksum == 0) {
- printf("/Multiboot");
- mbheader = h;
- return;
- }
- }
- mbheader = 0;
+ /* This piece of code is pretty stupid, since it always copies data, even
+ * if it is word aligned. This shouldn't matter too much on platforms that
+ * use the Multiboot spec, since the processors are usually reasonably fast
+ * and this code is only executed for the first 8KB of the image. Feel
+ * free to improve it, but be prepared to write quite a lot of code that
+ * deals with non-aligned data with respect to the image to load. */
+ while (len > 0) {
+ mbimgoffset++;
+ memcpy(mbbuffer + mboffset, data, 1);
+ mboffset++;
+ data++;
+ len--;
+ if (mboffset == 4) {
+ /* Accumulated a word into the buffer. */
+ h = (struct multiboot_header *)mbbuffer;
+ if (h->magic != MULTIBOOT_HEADER_MAGIC) {
+ /* Wrong magic, this cannot be the start of the header. */
+ mboffset = 0;
+ }
+ } else if (mboffset == 12) {
+ /* Accumulated the minimum header data into the buffer. */
+ h = (struct multiboot_header *)mbbuffer;
+ if (h->magic + h->flags + h->checksum != 0) {
+ /* Checksum error, not a valid header. Check for a possible
+ * header starting in the current flag/checksum field. */
+ if (h->flags == MULTIBOOT_HEADER_MAGIC) {
+ mboffset -= 4;
+ memmove(mbbuffer, mbbuffer + 4, mboffset);
+ } else if (h->checksum == MULTIBOOT_HEADER_MAGIC) {
+ mboffset -= 8;
+ memmove(mbbuffer, mbbuffer + 8, mboffset);
+ } else {
+ mboffset = 0;
+ }
+ } else {
+ printf("Multiboot... ");
+ mbheader = h;
+ if ((h->flags & 0xfffc) != 0) {
+ printf("\nERROR: Unsupported Multiboot requirements flags\n");
+ longjmp(restart_etherboot, -2);
+ }
+ break;
+ }
+ }
+ }
+ mbimgoffset += len;
}
static inline void multiboot_boot(unsigned long entry)
@@ -94,7 +148,7 @@ static inline void multiboot_boot(unsigned long entry)
* strings of the maximum size are possible. Note this buffer
* can overrun if a stupid file name is chosen. Oh well. */
c = cmdline;
- for (i = 0; KERNEL_BUF[i] != 0; i++) {
+ for (i = 0; KERNEL_BUF[i] != '\0'; i++) {
switch (KERNEL_BUF[i]) {
case ' ':
case '\\':
@@ -106,6 +160,11 @@ static inline void multiboot_boot(unsigned long entry)
}
*c++ = KERNEL_BUF[i];
}
+ if (addparam != NULL) {
+ *c++ = ' ';
+ memcpy(c, addparam, addparamlen);
+ c += addparamlen;
+ }
(void)sprintf(c, " -retaddr %#lX", virt_to_phys(xend32));
mbinfo.flags = MULTIBOOT_MMAP_VALID | MULTIBOOT_MEM_VALID |MULTIBOOT_CMDLINE_VALID;
@@ -139,5 +198,11 @@ static inline void multiboot_boot(unsigned long entry)
os_regs.eax = 0x2BADB002;
os_regs.ebx = virt_to_phys(&mbinfo);
xstart32(entry);
- longjmp(restart_etherboot, -2);
+ /* A Multiboot kernel by default never returns - there is nothing in the
+ * specification about what happens to the boot loader after the kernel has
+ * been started. Thus if the kernel returns it is definitely aware of the
+ * semantics involved (i.e. the "-retaddr" parameter). Do not treat this
+ * as an error, but restart with a fresh DHCP request in order to activate
+ * the menu again in case one is used. */
+ longjmp(restart_etherboot, 2);
}
diff --git a/src/arch/i386/firmware/pcbios/basemem.c b/src/arch/i386/firmware/pcbios/basemem.c
index 0bc9ca983..7dad640e3 100644
--- a/src/arch/i386/firmware/pcbios/basemem.c
+++ b/src/arch/i386/firmware/pcbios/basemem.c
@@ -130,8 +130,8 @@ void free_base_memory ( void *ptr, size_t size ) {
*/
for ( ; size_kb > 0 ; free_block++, size_kb-- ) {
/* Mark this block as unused */
- free_block->magic = FREE_BLOCK_MAGIC;
- free_block->size_kb = size_kb;
+ free_block->header.magic = FREE_BLOCK_MAGIC;
+ free_block->header.size_kb = size_kb;
}
/* Free up unused base memory */
@@ -161,12 +161,12 @@ static void free_unused_base_memory ( void ) {
* if this is not a free block
*/
if ( ( fbms == FBMS_MAX ) ||
- ( free_block->magic != FREE_BLOCK_MAGIC ) ) {
+ ( free_block->header.magic != FREE_BLOCK_MAGIC ) ) {
break;
}
/* Return memory to BIOS */
- fbms += free_block->size_kb;
+ fbms += free_block->header.size_kb;
DBG ( "Freed %d kB of base memory at [%hx:0000,%hx:0000), "
"%d kB now free\n",
diff --git a/src/arch/i386/image/nbi.c b/src/arch/i386/image/nbi.c
index f361aa945..f5d9e3826 100644
--- a/src/arch/i386/image/nbi.c
+++ b/src/arch/i386/image/nbi.c
@@ -4,22 +4,44 @@
#include "gateA20.h"
#include "osloader.h"
#include "etherboot.h"
+#include "errno.h"
-/* An NBI image header */
+/** @file
+ *
+ * NBI image format.
+ *
+ * The Net Boot Image format is defined by the "Draft Net Boot Image
+ * Proposal 0.3" by Jamie Honan, Gero Kuhlmann and Ken Yap. It is now
+ * considered to be a legacy format, but it still included because a
+ * large amount of software (e.g. nymph, LTSP) makes use of NBI files.
+ *
+ * Etherboot does not implement the INT 78 callback interface
+ * described by the NBI specification. For a callback interface on
+ * x86 architecture, use PXE.
+ *
+ */
+
+/**
+ * An NBI image header
+ *
+ * Note that the length field uses a peculiar encoding; use the
+ * NBI_LENGTH() macro to decode the actual header length.
+ *
+ */
struct imgheader {
- unsigned long magic;
+ unsigned long magic; /**< Magic number (NBI_MAGIC) */
union {
- unsigned char length;
- unsigned long flags;
+ unsigned char length; /**< Nibble-coded header length */
+ unsigned long flags; /**< Image flags */
};
- segoff_t location;
+ segoff_t location; /**< 16-bit seg:off header location */
union {
- segoff_t segoff;
- unsigned long linear;
+ segoff_t segoff; /**< 16-bit seg:off entry point */
+ unsigned long linear; /**< 32-bit entry point */
} execaddr;
} __attribute__ (( packed ));
-/* NBI magic number */
+/** NBI magic number */
#define NBI_MAGIC 0x1B031336UL
/* Interpretation of the "length" fields */
@@ -31,18 +53,24 @@ struct imgheader {
#define NBI_PROGRAM_RETURNS(flags) ( (flags) & ( 1 << 8 ) )
#define NBI_LINEAR_EXEC_ADDR(flags) ( (flags) & ( 1 << 31 ) )
-/* NBI header length */
+/** NBI header length */
#define NBI_HEADER_LENGTH 512
-/* An NBI segment header */
+/**
+ * An NBI segment header
+ *
+ * Note that the length field uses a peculiar encoding; use the
+ * NBI_LENGTH() macro to decode the actual header length.
+ *
+ */
struct segheader {
- unsigned char length;
- unsigned char vendortag;
+ unsigned char length; /**< Nibble-coded header length */
+ unsigned char vendortag; /**< Vendor-defined private tag */
unsigned char reserved;
- unsigned char flags;
- unsigned long loadaddr;
- unsigned long imglength;
- unsigned long memlength;
+ unsigned char flags; /**< Segment flags */
+ unsigned long loadaddr; /**< Load address */
+ unsigned long imglength; /**< Segment length in NBI file */
+ unsigned long memlength; /**< Segment length in memory */
};
/* Interpretation of the "flags" fields */
@@ -53,28 +81,41 @@ struct segheader {
#define NBI_LOADADDR_BEFORE 0x03
#define NBI_LAST_SEGHEADER(flags) ( (flags) & ( 1 << 2 ) )
-/* Info passed to NBI image */
+/** Info passed to NBI image */
static struct ebinfo loaderinfo = {
VERSION_MAJOR, VERSION_MINOR,
0
};
-/*
+/**
* Determine whether or not this is a valid NBI image
*
+ * @v start Address of the image
+ * @v len Length of the image
+ * @v context NBI image context
+ * @ret True Image is a valid NBI image
+ * @ret False Image is not a valid NBI image
+ * @err EBADIMG Image is not a valid NBI image
+ *
+ * "context" is filled in with a context pointer suitable for passing to
+ * nbi_load() and nbi_boot().
+ *
*/
static int nbi_probe ( physaddr_t start, off_t len, void **context ) {
static struct imgheader imgheader;
if ( (unsigned)len < sizeof ( imgheader ) ) {
DBG ( "NBI image too small\n" );
+ errno = EBADIMG;
return 0;
}
copy_from_phys ( &imgheader, start, sizeof ( imgheader ) );
- if ( imgheader.magic != NBI_MAGIC )
+ if ( imgheader.magic != NBI_MAGIC ) {
+ errno = EBADIMG;
return 0;
+ }
/* Record image context */
DBG ( "NBI found valid image\n" );
@@ -82,9 +123,17 @@ static int nbi_probe ( physaddr_t start, off_t len, void **context ) {
return 1;
}
-/*
+/**
* Prepare a segment for an NBI image
*
+ * @v dest Address of segment
+ * @v imglen Length of initialised-data portion of the segment
+ * @v memlen Total length of the segment
+ * @v src Source for initialised data
+ * @ret True Segment can be used
+ * @ret False Segment cannot be used
+ * @err other As returned by prep_segment()
+ *
*/
static int nbi_prepare_segment ( physaddr_t dest, off_t imglen, off_t memlen,
physaddr_t src __unused ) {
@@ -93,9 +142,15 @@ static int nbi_prepare_segment ( physaddr_t dest, off_t imglen, off_t memlen,
return prep_segment ( dest, dest + imglen, dest + memlen );
}
-/*
+/**
* Load a segment for an NBI image
*
+ * @v dest Address of segment
+ * @v imglen Length of initialised-data portion of the segment
+ * @v memlen Total length of the segment
+ * @v src Source for initialised data
+ * @ret True Always
+ *
*/
static int nbi_load_segment ( physaddr_t dest, off_t imglen,
off_t memlen __unused, physaddr_t src ) {
@@ -104,9 +159,18 @@ static int nbi_load_segment ( physaddr_t dest, off_t imglen,
return 1;
}
-/*
+/**
* Process segments of an NBI image
*
+ * @v start Address of the image
+ * @v len Length of the image
+ * @v imgheader Image header information
+ * @v process Function to call for each segment
+ * @ret True All segments were processed successfully
+ * @ret False An error occurred processing a segment
+ * @err EBADIMG Image is not a valid NBI image
+ * @err other As returned by the "process" function
+ *
*/
static int nbi_process_segments ( physaddr_t start, off_t len,
struct imgheader *imgheader,
@@ -136,6 +200,7 @@ static int nbi_process_segments ( physaddr_t start, off_t len,
if ( sh.length == 0 ) {
/* Avoid infinite loop? */
DBG ( "NBI invalid segheader length 0\n" );
+ errno = EBADIMG;
return 0;
}
@@ -159,8 +224,8 @@ static int nbi_process_segments ( physaddr_t start, off_t len,
- sh.loadaddr;
break;
default:
- DBG ( "NBI can't count up to three\n" );
- return 0;
+ /* Cannot be reached */
+ DBG ( "NBI can't count up to three!\n" );
}
/* Process this segment */
@@ -175,6 +240,7 @@ static int nbi_process_segments ( physaddr_t start, off_t len,
sh_off += NBI_LENGTH ( sh.length );
if ( sh_off >= NBI_HEADER_LENGTH ) {
DBG ( "NBI header overflow\n" );
+ errno = EBADIMG;
return 0;
}
@@ -183,22 +249,35 @@ static int nbi_process_segments ( physaddr_t start, off_t len,
if ( offset != len ) {
DBG ( "NBI length mismatch (file %d, metadata %d)\n",
len, offset );
+ errno = EBADIMG;
return 0;
}
return 1;
}
-/*
+/**
* Load an NBI image into memory
*
+ * @v start Address of image
+ * @v len Length of image
+ * @v context NBI context (as returned by nbi_probe())
+ * @ret True Image loaded into memory
+ * @ret False Image not loaded into memory
+ * @err EBADIMG Image is not a valid NBI image
+ * @err other As returned by nbi_process_segments()
+ * @err other As returned by nbi_prepare_segment()
+ * @err other As returned by nbi_load_segment()
+ *
*/
static int nbi_load ( physaddr_t start, off_t len, void *context ) {
struct imgheader *imgheader = context;
/* If we don't have enough data give up */
- if ( len < NBI_HEADER_LENGTH )
+ if ( len < NBI_HEADER_LENGTH ) {
+ errno = EBADIMG;
return 0;
+ }
DBG ( "NBI placing header at %hx:%hx\n",
imgheader->location.segment, imgheader->location.offset );
@@ -220,9 +299,14 @@ static int nbi_load ( physaddr_t start, off_t len, void *context ) {
return 1;
}
-/*
+/**
* Boot a 16-bit NBI image
*
+ * @v imgheader Image header information
+ * @ret Never NBI program booted successfully
+ * @ret False NBI program returned
+ * @err EIMGRET NBI program returned
+ *
*/
static int nbi_boot16 ( struct imgheader *imgheader ) {
uint16_t basemem_bootp;
@@ -256,12 +340,23 @@ static int nbi_boot16 ( struct imgheader *imgheader ) {
CLOBBER ( "eax", "ecx", "edx", "ebp" ) );
BASEMEM_PARAMETER_DONE ( bootp_data );
+ errno = EIMGRET;
return 0;
}
-/*
+/**
* Boot a 32-bit NBI image
*
+ * @v imgheader Image header information
+ * @ret False NBI program should not have returned
+ * @ret other As returned by NBI program
+ * @err EIMGRET NBI program should not have returned
+ *
+ * To distinguish between the case of an NBI program returning false,
+ * and an NBI program that should not have returned, check errno.
+ * errno will be set to EIMGRET only if the NBI program should not
+ * have returned.
+ *
*/
static int nbi_boot32 ( struct imgheader *imgheader ) {
int rc = 0;
@@ -270,6 +365,7 @@ static int nbi_boot32 ( struct imgheader *imgheader ) {
imgheader->execaddr.linear );
/* no gateA20_unset for PM call */
+ errno = ENOERR;
rc = xstart32 ( imgheader->execaddr.linear,
virt_to_phys ( &loaderinfo ),
( ( imgheader->location.segment << 4 ) +
@@ -278,15 +374,24 @@ static int nbi_boot32 ( struct imgheader *imgheader ) {
printf ( "Secondary program returned %d\n", rc );
if ( ! NBI_PROGRAM_RETURNS ( imgheader->flags ) ) {
/* We shouldn't have returned */
+ errno = EIMGRET;
rc = 0;
}
return rc;
}
-/*
+/**
* Boot a loaded NBI image
*
+ * @v context NBI context (as returned by nbi_probe())
+ * @ret Never NBI program booted successfully
+ * @ret False NBI program should not have returned
+ * @ret other As returned by NBI program
+ * @err EIMGRET NBI program should not have returned
+ *
+ * See also nbi_boot16() and nbi_boot32().
+ *
*/
static int nbi_boot ( void *context ) {
struct imgheader *imgheader = context;
@@ -298,6 +403,7 @@ static int nbi_boot ( void *context ) {
}
}
+/** Declaration of the NBI image format */
static struct image nbi_image __image = {
.name = "NBI",
.probe = nbi_probe,
diff --git a/src/arch/i386/core/pxe_loader.c b/src/arch/i386/image/pxe_image.c
index 1b6118917..bd1bad35e 100644
--- a/src/arch/i386/core/pxe_loader.c
+++ b/src/arch/i386/image/pxe_image.c
@@ -13,7 +13,6 @@
#include "etherboot.h"
#include "pxe_callbacks.h"
-#include "pxe_export.h"
#include "pxe.h"
unsigned long pxe_load_offset;
diff --git a/src/arch/i386/include/basemem.h b/src/arch/i386/include/basemem.h
index 6e7c22dda..289824eb0 100644
--- a/src/arch/i386/include/basemem.h
+++ b/src/arch/i386/include/basemem.h
@@ -19,7 +19,7 @@ struct free_base_memory_header {
};
union free_base_memory_block {
- struct free_base_memory_header;
+ struct free_base_memory_header header;
char bytes[1024];
};
diff --git a/src/arch/i386/include/bochs.h b/src/arch/i386/include/bochs.h
index 73f43c364..9d090fc12 100644
--- a/src/arch/i386/include/bochs.h
+++ b/src/arch/i386/include/bochs.h
@@ -1,9 +1,16 @@
#ifndef BOCHS_H
#define BOCHS_H
-/*
- * This file defines "bochsbp", the magic breakpoint instruction that
- * is incredibly useful when debugging under bochs.
+/** @file
+ *
+ * bochs breakpoints
+ *
+ * This file defines @c bochsbp, the magic breakpoint instruction that
+ * is incredibly useful when debugging under bochs. This file should
+ * never be included in production code.
+ *
+ * Use the pseudo-instruction @c bochsbp in assembly code, or the
+ * bochsbp() function in C code.
*
*/
@@ -15,7 +22,7 @@
#else /* ASSEMBLY */
-/* Breakpoint for when debugging under bochs */
+/** Breakpoint for when debugging under bochs */
static inline void bochsbp ( void ) {
__asm__ __volatile__ ( "xchgw %bx, %bx" );
}
diff --git a/src/arch/i386/include/hooks.h b/src/arch/i386/include/hooks.h
index 95b9aaa36..3cef262f9 100644
--- a/src/arch/i386/include/hooks.h
+++ b/src/arch/i386/include/hooks.h
@@ -1,6 +1,6 @@
#ifndef HOOKS_H
#define HOOKS_H
-extern void arch_main ( struct i386_all_regs *regs );
+extern void arch_main ( struct i386_all_regs *ix86 );
#endif /* HOOKS_H */
diff --git a/src/arch/i386/include/librm.h b/src/arch/i386/include/librm.h
index 2edc10968..1b82a9828 100644
--- a/src/arch/i386/include/librm.h
+++ b/src/arch/i386/include/librm.h
@@ -17,8 +17,8 @@
/* Real-mode call parameter block, as passed to real_call */
struct real_call_params {
- struct i386_seg_regs;
- struct i386_regs;
+ struct i386_seg_regs segs;
+ struct i386_regs regs;
segoff_t rm_code;
segoff_t reserved;
} PACKED;
diff --git a/src/arch/i386/include/pxe_addr.h b/src/arch/i386/include/pxe_addr.h
new file mode 100644
index 000000000..954551e80
--- /dev/null
+++ b/src/arch/i386/include/pxe_addr.h
@@ -0,0 +1,17 @@
+/*
+ * Architecture-specific portion of pxe.h for Etherboot
+ *
+ * This file has to define the types SEGOFF16_t, SEGDESC_t and
+ * SEGSEL_t for use in other PXE structures. See pxe.h for details.
+ */
+
+#ifndef PXE_ADDR_H
+#define PXE_ADDR_H
+
+#define IS_NULL_SEGOFF16(x) ( ( (x).segment == 0 ) && ( (x).offset == 0 ) )
+#define SEGOFF16_TO_PTR(x) ( VIRTUAL( (x).segment, (x).offset ) )
+#define PTR_TO_SEGOFF16(ptr,segoff16) \
+ (segoff16).segment = SEGMENT(ptr); \
+ (segoff16).offset = OFFSET(ptr);
+
+#endif /* PXE_ADDR_H */
diff --git a/src/arch/i386/include/pxe_callbacks.h b/src/arch/i386/include/pxe_callbacks.h
index cf5a7a878..974a3c30c 100644
--- a/src/arch/i386/include/pxe_callbacks.h
+++ b/src/arch/i386/include/pxe_callbacks.h
@@ -5,12 +5,12 @@
#define PXE_CALLBACKS_H
#include "etherboot.h"
-#include "pxe.h"
+#include "pxe_types.h"
typedef struct {
- segoff_t orig_retaddr;
- uint16_t opcode;
- segoff_t segoff;
+ SEGOFF16_t orig_retaddr;
+ UINT16_t opcode;
+ SEGOFF16_t segoff;
} PACKED pxe_call_params_t;
/*
@@ -22,7 +22,7 @@ typedef struct {
/* Function prototypes
*/
-extern pxe_stack_t * install_pxe_stack ( void *base );
+extern struct pxe_stack * install_pxe_stack ( void *base );
extern void use_undi_ds_for_rm_stack ( uint16_t ds );
extern int hook_pxe_stack ( void );
extern int unhook_pxe_stack ( void );
diff --git a/src/arch/i386/include/pxe_types.h b/src/arch/i386/include/pxe_types.h
deleted file mode 100644
index 45736a2bf..000000000
--- a/src/arch/i386/include/pxe_types.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Architecture-specific portion of pxe.h for Etherboot
- *
- * This file has to define the types SEGOFF16_t, SEGDESC_t and
- * SEGSEL_t for use in other PXE structures. See pxe.h for details.
- */
-
-#ifndef PXE_TYPES_H
-#define PXE_TYPES_H
-
-/* SEGOFF16_t defined in separate header
- */
-#include "realmode.h"
-typedef segoff_t I386_SEGOFF16_t;
-#define SEGOFF16_t I386_SEGOFF16_t
-
-#define IS_NULL_SEGOFF16(x) ( ( (x).segment == 0 ) && ( (x).offset == 0 ) )
-#define SEGOFF16_TO_PTR(x) ( VIRTUAL( (x).segment, (x).offset ) )
-#define PTR_TO_SEGOFF16(ptr,segoff16) \
- (segoff16).segment = SEGMENT(ptr); \
- (segoff16).offset = OFFSET(ptr);
-
-typedef struct {
- uint16_t Seg_Addr;
- uint32_t Phy_Addr;
- uint16_t Seg_Size;
-} PACKED I386_SEGDESC_t; /* PACKED is required, otherwise gcc pads
- * this out to 12 bytes -
- * mbrown@fensystems.co.uk (mcb30) 17/5/03 */
-#define SEGDESC_t I386_SEGDESC_t
-
-typedef uint16_t I386_SEGSEL_t;
-#define SEGSEL_t I386_SEGSEL_t
-
-#endif /* PXE_TYPES_H */
diff --git a/src/arch/i386/include/realmode.h b/src/arch/i386/include/realmode.h
index cd6fcfc73..fe0111846 100644
--- a/src/arch/i386/include/realmode.h
+++ b/src/arch/i386/include/realmode.h
@@ -12,11 +12,6 @@
*
*/
-/* All i386 registers, as passed in by prot_call or kir_call */
-struct real_mode_regs {
- struct i386_all_regs;
-} PACKED;
-
/* Segment:offset structure. Note that the order within the structure
* is offset:segment.
*/
diff --git a/src/arch/i386/include/registers.h b/src/arch/i386/include/registers.h
index 155fffbdf..666532389 100644
--- a/src/arch/i386/include/registers.h
+++ b/src/arch/i386/include/registers.h
@@ -1,9 +1,25 @@
#ifndef REGISTERS_H
#define REGISTERS_H
+/** @file
+ *
+ * i386 registers.
+ *
+ * This file defines data structures that allow easy access to i386
+ * register dumps.
+ *
+ */
+
+#include "compiler.h" /* for doxygen */
#include "stdint.h"
-/* Basic 16-bit and 32-bit register types */
+/**
+ * A 16-bit general register.
+ *
+ * This type encapsulates a 16-bit register such as %ax, %bx, %cx,
+ * %dx, %si, %di, %bp or %sp.
+ *
+ */
typedef union {
struct {
union {
@@ -15,12 +31,33 @@ typedef union {
uint16_t word;
} PACKED reg16_t;
+/**
+ * A 32-bit general register.
+ *
+ * This type encapsulates a 32-bit register such as %eax, %ebx, %ecx,
+ * %edx, %esi, %edi, %ebp or %esp.
+ *
+ */
typedef union {
- reg16_t;
+ struct {
+ union {
+ uint8_t l;
+ uint8_t byte;
+ };
+ uint8_t h;
+ } PACKED;
+ uint16_t word;
uint32_t dword;
} PACKED reg32_t;
-/* As created by pushal / read by popal */
+/**
+ * A 32-bit general register dump.
+ *
+ * This is the data structure that is created on the stack by the @c
+ * pushal instruction, and can be read back using the @c popal
+ * instruction.
+ *
+ */
struct i386_regs {
union {
uint16_t di;
@@ -72,7 +109,31 @@ struct i386_regs {
};
} PACKED;
-/* Our pushal/popal equivalent for segment registers */
+/**
+ * A segment register dump.
+ *
+ * The i386 has no equivalent of the @c pushal or @c popal
+ * instructions for the segment registers. We adopt the convention of
+ * always using the sequences
+ *
+ * @code
+ *
+ * pushw %gs ; pushw %fs ; pushw %es ; pushw %ds ; pushw %ss ; pushw %cs
+ *
+ * @endcode
+ *
+ * and
+ *
+ * @code
+ *
+ * addw $4, %sp ; popw %ds ; popw %es ; popw %fs ; popw %gs
+ *
+ * @endcode
+ *
+ * This is the data structure that is created and read back by these
+ * instruction sequences.
+ *
+ */
struct i386_seg_regs {
uint16_t cs;
uint16_t ss;
@@ -82,11 +143,37 @@ struct i386_seg_regs {
uint16_t gs;
} PACKED;
-/* All i386 registers, as passed in by prot_call or kir_call */
+/**
+ * A full register dump.
+ *
+ * This data structure is created by the instructions
+ *
+ * @code
+ *
+ * pushfl
+ * pushal
+ * pushw %gs ; pushw %fs ; pushw %es ; pushw %ds ; pushw %ss ; pushw %cs
+ *
+ * @endcode
+ *
+ * and can be read back using the instructions
+ *
+ * @code
+ *
+ * addw $4, %sp ; popw %ds ; popw %es ; popw %fs ; popw %gs
+ * popal
+ * popfl
+ *
+ * @endcode
+ *
+ * prot_call() and kir_call() create this data structure on the stack
+ * and pass in a pointer to this structure.
+ *
+ */
struct i386_all_regs {
- struct i386_seg_regs;
- struct i386_regs;
- uint32_t i386_flags;
+ struct i386_seg_regs segs;
+ struct i386_regs regs;
+ uint32_t flags;
} PACKED;
#endif /* REGISTERS_H */
diff --git a/src/arch/i386/include/stdint.h b/src/arch/i386/include/stdint.h
index b9ade4e00..c801cf6f4 100644
--- a/src/arch/i386/include/stdint.h
+++ b/src/arch/i386/include/stdint.h
@@ -16,4 +16,16 @@ typedef signed long long int64_t;
typedef unsigned long physaddr_t;
+typedef signed char s8;
+typedef unsigned char u8;
+
+typedef signed short s16;
+typedef unsigned short u16;
+
+typedef signed int s32;
+typedef unsigned int u32;
+
+typedef signed long long s64;
+typedef unsigned long long u64;
+
#endif /* STDINT_H */
diff --git a/src/arch/i386/include/virtaddr.h b/src/arch/i386/include/virtaddr.h
index d48b6c6cd..4d248b0ac 100644
--- a/src/arch/i386/include/virtaddr.h
+++ b/src/arch/i386/include/virtaddr.h
@@ -46,7 +46,8 @@ static inline void * phys_to_virt ( unsigned long phys_addr ) {
return ( void * ) ( phys_addr - virt_offset );
}
-static inline void copy_to_phys ( physaddr_t dest, void *src, size_t len ) {
+static inline void copy_to_phys ( physaddr_t dest, const void *src,
+ size_t len ) {
memcpy ( phys_to_virt ( dest ), src, len );
}
diff --git a/src/arch/i386/prefix/hdprefix.S b/src/arch/i386/prefix/hdprefix.S
new file mode 100644
index 000000000..38e62bc3c
--- /dev/null
+++ b/src/arch/i386/prefix/hdprefix.S
@@ -0,0 +1,296 @@
+/****************************************************************\
+
+hdprefix.S Copyright (C) 2005 Per Dalgas Jakobsen
+
+This code has been inspired/derived by the OSLoader by Vladislav Aleksandrov.
+http://www.programmersheaven.com/zone5/cat469/40546.htm.
+
+This software may be used and distributed according to the terms
+of the GNU Public License (GPL), incorporated herein by reference.
+
+hdprefix.S is loaded at 0x0000:0x7c00 by the bios-startup routines.
+
+Actions performed by hdprefix:
+1) Load the MBR to LOADSEG:0
+2) Check which partition is active (or try first partition if none active)
+3) Check wether LBA is supported.
+3a) LBA
+3a1) Load PAYLOAD_SECTS sectors from chosen partition to LOADSEG:0
+3b) CHS (standard)
+3b1) Load PAYLOAD_SECTS sectors from chosen partition to LOADSEG:0
+4) Check loaded bootsector for BOOTMAGIC code.
+5) Jump to payload LOADSEG:ENTRYPOINT.
+
+Output with failure points (!#):
+---
+Loading (!1)partition #
+Std. BIOS(!2) | Ext. BIOS(!3)
+Booting...(!4)
+(!5)
+---
+
+!1: Failed to load MBR with Int13,ah=2.
+!2: Failed to load bootrecord+payload with Int13,ah=2.
+!3: Failed to load bootrecord+payload with Int13,ah=42.
+!4: Invalid BOOTMAGIC in loaded bootrecord.
+!5: Jumping to payload.
+
+\*****************************************************************/
+
+.equ BOOTSEG, 0x07c0
+.equ LOADSEG, 0x1000
+.equ ENTRYPOINT, _start
+
+.equ BOOTMAGIC, 0x0aa55
+
+.equ partition_table, 0x1be
+.equ partition_rec_size, 0x10
+
+.equ boot_ind, 0 /* 80h=active */
+.equ start_head, 1
+.equ start_sector, 2 /* bits 0-5 */
+.equ start_cyl, 3 /* bits 8,9 in bits 6,7 of sector */
+.equ os_ind, 4 /* os indicator */
+.equ end_head, 5
+.equ end_sector, 6 /* bits 0-5 */
+.equ end_track, 7 /* bits 8,9 in bits 6,7 of sector */
+.equ nsect, 8 /* sectors preceding partition */
+.equ lenght, 0x0c /* length of partition in sectors */
+
+/-------------------------------------------------------------
+
+ .arch i386
+ .text
+ .section ".prefix", "ax", @progbits
+ .code16
+
+bootstart:
+ jmp $BOOTSEG,$_go /* reload cs:ip */
+
+
+/****************************************************************/
+/* support routines. */
+/*--------------------------------------------------------------*/
+_failed:
+ movw $BOOTSEG,%ax
+ movw %ax,%ds
+ movw $_failed_msg_end-_failed_msg,%cx
+ movw $_failed_msg,%si
+ call _print_str
+
+ /* stop execution - should probably have option to auto-reboot after delay. */
+_failed_loop:
+ jmp _failed_loop
+
+/*--------------------------------------------------------------*/
+_print_str:
+ /* cx = count, ds:si = string. */
+ movw $0x0007,%bx
+ movb $0x0e,%ah
+_print_loop:
+ lodsb
+ int $0x10
+ loop _print_loop
+ ret
+
+/*--------------------------------------------------------------*/
+_print_char:
+ /* al = char. */
+ movw $0x0007,%bx
+ movb $0x0e,%ah
+ int $0x10
+ ret
+
+/*--------------------------------------------------------------*/
+_print_nl:
+ /* - */
+ movb $0x0d,%al
+ call _print_char
+ movb $0x0a,%al
+ call _print_char
+ ret
+
+/*--------------------------------------------------------------*/
+_print_hex:
+ /* dx = value */
+ movb $0x0e,%ah /* write char, tty mode */
+ movw $0x0007,%bx /* page 0, attribute 7 (normal) */
+ call _print_digit
+ call _print_digit
+ call _print_digit
+ /* fall through */
+_print_digit:
+ rolw $4,%dx /* rotate so that lowest 4 bits are used */
+ movb $0x0f,%al /* mask for nibble */
+ andb %dl,%al
+ addb $0x90,%al /* convert al to ascii hex (four instructions) */
+ daa
+ adcb $0x40,%al
+ daa
+ int $0x10
+ ret
+
+/****************************************************************/
+
+
+_go:
+ cli
+ movw $BOOTSEG,%ax
+ movw %ax,%ds
+ movw %ax,%ss
+ movw $0x2000,%sp /* good large stack. */
+ sti
+ cld
+ movw $LOADSEG,%ax
+ movw %ax,%es
+
+ movw $_load_msg_end-_load_msg,%cx
+ movw $_load_msg,%si
+ call _print_str
+
+/*--- load MBR so we can use its partition table. ---*/
+ xorw %bx,%bx
+ movw $0x0001,%cx /* chs: 0,0,1 */
+ movb %bh,%dh /* - */
+ movb $0x80,%dl
+ movw $0x0201,%ax /* read one sector (MBR) */
+ int $0x13
+ jc _failed
+
+/*--- find the active partition ---*/
+ movw $_part_msg_end-_part_msg,%cx
+ movw $_part_msg,%si
+ call _print_str
+
+ movw $partition_table,%di
+ movw $4,%cx
+_partition_loop:
+ cmpb $0x80,%es:(%di) /* active? */
+ je _partition_found
+ addw $partition_rec_size,%di
+ loop _partition_loop
+
+ /*- no partitions marked active - use 1. partition. */
+ movw $partition_table,%di
+ movw $4,%cx
+
+_partition_found:
+ movb $'5',%al /* convert to ascii */
+ subb %cl,%al
+ call _print_char
+ call _print_nl
+
+/*--- check for lba support ---*/
+ movw $0x55aa,%bx
+ movb $0x80,%dl
+ movb $0x41,%ah
+ int $0x13
+ jc __bios
+ cmpw $0x0aa55,%bx
+ jnz __bios
+ testb $1,%cl
+ jz __bios
+
+/*--- use lba bios calls to read sectors ---*/
+_lba:
+ movw $_extbios_msg_end-_extbios_msg,%cx
+ movw $_extbios_msg,%si
+ call _print_str
+
+ movw %es:nsect(%di),%ax
+ movw %ax,_bios_lba_low
+ movw %es:nsect+2(%di),%ax
+ movw %ax,_bios_lba_high
+ movb $0x80,%dl
+ movw $_disk_address_packet,%si
+ movw $0x4200,%ax /* read */
+ int $0x13
+ jc _failed
+ jmp __loaded
+
+/*--- use standard bios calls to read sectors ---*/
+__bios:
+ movw $_stdbios_msg_end-_stdbios_msg,%cx
+ movw $_stdbios_msg,%si
+ call _print_str
+
+ movw _disk_address_packet+2(,1),%ax /* only low byte is used. */
+ xorw %bx,%bx
+ movw %es:start_sector(%di),%cx
+ movb %es:start_head(%di),%dh
+ movb $0x80,%dl
+ movb $0x02,%ah
+ int $0x13
+ jc _failed
+
+__loaded:
+ movw $_boot_msg_end-_boot_msg,%cx
+ movw $_boot_msg,%si
+ call _print_str
+
+ /* check if it has a valid bootrecord. */
+ cmpw $BOOTMAGIC,%es:510(,1)
+ jne _failed
+ call _print_nl
+
+ /* call the payload. */
+ pushl $0 /* No parameters to preserve for exit path */
+ pushw $0 /* Use prefix exit path mechanism */
+ jmp $LOADSEG,$ENTRYPOINT
+
+ .section ".text16", "ax", @progbits
+ .globl prefix_exit
+prefix_exit:
+ int $0x19 /* should try to boot machine */
+ .globl prefix_exit_end
+prefix_exit_end:
+ .previous
+
+
+/*--------------------------------------------------------------*/
+
+_load_msg: .ascii "Loading "
+_load_msg_end:
+_part_msg: .ascii "partition "
+_part_msg_end:
+_boot_msg: .ascii "Booting..."
+_boot_msg_end:
+_stdbios_msg: .ascii "Std. BIOS\r\n"
+_stdbios_msg_end:
+_extbios_msg: .ascii "Ext. BIOS\r\n"
+_extbios_msg_end:
+_failed_msg: .ascii "FAILED!!!\r\n"
+_failed_msg_end:
+
+
+/*--------------------------------------------------------------*/
+
+_disk_address_packet:
+ .byte 0x10 /* size of the packet */
+ .byte 0 /* reserved */
+ .word _verbatim_size_sct /* number of sectors to read */
+ .word 0x0000 /* offset */
+ .word LOADSEG /* segment of buffer */
+_bios_lba_low: .word 0
+_bios_lba_high: .word 0
+ .word 0
+ .word 0
+
+ .rept 32
+ .byte 0
+ .endr
+
+
+/*--- Partition table ------------------------------------------*/
+
+ .org 446, 0
+ .rept 64
+ .byte 0
+ .endr
+
+
+/*--- Magic code -----------------------------------------------*/
+ .org 510, 0
+ .word BOOTMAGIC
+
+/*** END ********************************************************/
diff --git a/src/arch/i386/prefix/int19exit.c b/src/arch/i386/prefix/int19exit.c
index e7be06244..e1333926c 100644
--- a/src/arch/i386/prefix/int19exit.c
+++ b/src/arch/i386/prefix/int19exit.c
@@ -1,13 +1,31 @@
#include "bochs.h"
#include "realmode.h"
-/*
- * The "exit via INT 19" exit path. INT 19 is the old (pre-BBS) "boot
- * system" interrupt.
+/** @file
+ *
+ * The "exit via INT 19" exit path.
+ *
+ * INT 19 is the old (pre-BBS) "boot system" interrupt. It is
+ * conventionally used now to return from a failed boot from floppy
+ * disk.
*
*/
-void exit_via_int19 ( struct real_mode_regs *rm_regs ) {
+/**
+ * Exit via INT19
+ *
+ * @v ix86 i386 register values to be loaded on exit
+ * @ret Never -
+ * @err None -
+ *
+ * Exit back to the BIOS by switching to real mode, reloading the
+ * registers as they were before Etherboot started, and executing INT
+ * 19.
+ *
+ * @bug Not yet implemented
+ *
+ */
+void exit_via_int19 ( struct i386_all_regs *ix86 ) {
bochsbp();
/* Placeholder */
}
diff --git a/src/arch/i386/prefix/romprefix.S b/src/arch/i386/prefix/romprefix.S
index 9bdc4a024..4a5bd2e68 100644
--- a/src/arch/i386/prefix/romprefix.S
+++ b/src/arch/i386/prefix/romprefix.S
@@ -110,9 +110,9 @@ UNDIROMID:
.byte 0 /* Structure revision */
.byte 0,1,2 /* PXE version 2.1.0 */
.word UNDILoader - _prefix /* Offset to loader routine */
- .word UNDIStackSize /* Stack segment size */
- .word UNDIDataSize /* Data segment size */
- .word UNDICodeSize /* Code segment size */
+ .word _real_mode_stack_size /* Stack segment size */
+ .word _real_mode_stack_size /* Data segment size */
+ .word _pxe_stack_size /* Code segment size */
.ascii "PCIR"
/* The code segment contains our pxe_stack_t plus the PXE and
diff --git a/src/arch/i386/prefix/select_isapnp.c b/src/arch/i386/prefix/select_isapnp.c
index 54ac1c9a3..6a539eb5e 100644
--- a/src/arch/i386/prefix/select_isapnp.c
+++ b/src/arch/i386/prefix/select_isapnp.c
@@ -11,7 +11,7 @@
* would cause linker symbol pollution.
*
*/
-void i386_select_isapnp_device ( struct i386_all_regs *regs ) {
+void i386_select_isapnp_device ( struct i386_all_regs *ix86 ) {
/*
* PnP BIOS passes card select number in %bx and read port
* address in %dx.
@@ -23,10 +23,10 @@ void i386_select_isapnp_device ( struct i386_all_regs *regs ) {
} u;
/* Set ISAPnP read port */
- isapnp_read_port = regs->dx;
+ isapnp_read_port = ix86->regs.dx;
/* Select ISAPnP bus and specified CSN as first boot device */
memset ( &u, 0, sizeof ( u ) );
- u.isapnp_loc.csn = regs->bx;
+ u.isapnp_loc.csn = ix86->regs.bx;
select_device ( &dev, &isapnp_driver, &u.bus_loc );
}
diff --git a/src/arch/i386/prefix/select_pci.c b/src/arch/i386/prefix/select_pci.c
index c9a62d526..e143b992a 100644
--- a/src/arch/i386/prefix/select_pci.c
+++ b/src/arch/i386/prefix/select_pci.c
@@ -11,7 +11,7 @@
* that would cause linker symbol pollution.
*
*/
-void i386_select_pci_device ( struct i386_all_regs *regs ) {
+void i386_select_pci_device ( struct i386_all_regs *ix86 ) {
/*
* PCI BIOS passes busdevfn in %ax
*
@@ -23,6 +23,6 @@ void i386_select_pci_device ( struct i386_all_regs *regs ) {
/* Select PCI bus and specified busdevfn as first boot device */
memset ( &u, 0, sizeof ( u ) );
- u.pci_loc.busdevfn = regs->ax;
+ u.pci_loc.busdevfn = ix86->regs.ax;
select_device ( &dev, &pci_driver, &u.bus_loc );
}
diff --git a/src/arch/i386/transitions/libkir.S b/src/arch/i386/transitions/libkir.S
index 79a0aa00f..e0d6c57c2 100644
--- a/src/arch/i386/transitions/libkir.S
+++ b/src/arch/i386/transitions/libkir.S
@@ -135,12 +135,12 @@ kir_to_ext:
*
* Call a specific C function in the internal code. The prototype of
* the C function must be
- * void function ( struct real_mode_regs *rm_regs );
- * rm_regs will point to a struct containing the real-mode registers
+ * void function ( struct i386_all_resg *ix86 );
+ * ix86 will point to a struct containing the real-mode registers
* at entry to kir_call.
*
* All registers will be preserved across kir_call(), unless the C
- * function explicitly overwrites values in rm_regs. Interrupt status
+ * function explicitly overwrites values in ix86. Interrupt status
* will also be preserved.
*
* Parameters:
@@ -151,7 +151,7 @@ kir_to_ext:
* lcall $UNDI_CS, $kir_call
* addw $2, %sp
* to call in to the C function
- * void pxe_api_call ( struct real_mode_regs *rm_regs );
+ * void pxe_api_call ( struct i386_all_regs *ix86 );
****************************************************************************
*/
@@ -190,7 +190,7 @@ kir_call:
pushl %cs:ext_ds_and_es
pushl %cs:ext_cs_and_ss
- /* Push &rm_regs on stack and call function */
+ /* Push &ix86 on stack and call function */
pushl %esp
data32 call *%cs:save_function
popl %eax /* discard */
diff --git a/src/arch/i386/transitions/librm.S b/src/arch/i386/transitions/librm.S
index 6e2f12292..2e6ac47bb 100644
--- a/src/arch/i386/transitions/librm.S
+++ b/src/arch/i386/transitions/librm.S
@@ -106,11 +106,11 @@
/* Size of various C data structures */
#define SIZEOF_I386_SEG_REGS 12
#define SIZEOF_I386_REGS 32
-#define SIZEOF_I386_ALL_REGS ( SIZEOF_I386_SEG_REGS + SIZEOF_I386_REGS )
+#define SIZEOF_REAL_MODE_REGS ( SIZEOF_I386_SEG_REGS + SIZEOF_I386_REGS )
#define SIZEOF_I386_FLAGS 4
-#define SIZEOF_REAL_MODE_REGS ( SIZEOF_I386_ALL_REGS + SIZEOF_I386_FLAGS )
+#define SIZEOF_I386_ALL_REGS ( SIZEOF_REAL_MODE_REGS + SIZEOF_I386_FLAGS )
#define SIZEOF_SEGOFF_T 4
-#define SIZEOF_REAL_CALL_PARAMS ( SIZEOF_I386_ALL_REGS + 2 * SIZEOF_SEGOFF_T )
+#define SIZEOF_REAL_CALL_PARAMS ( SIZEOF_REAL_MODE_REGS + 2 * SIZEOF_SEGOFF_T )
.text
.arch i386
@@ -461,12 +461,12 @@ p2r_ljmp:
*
* Call a specific C function in the protected-mode code. The
* prototype of the C function must be
- * void function ( struct real_mode_regs *rm_regs );
- * rm_regs will point to a struct containing the real-mode registers
+ * void function ( struct i386_all_regs *ix86 );
+ * ix86 will point to a struct containing the real-mode registers
* at entry to prot_call.
*
* All registers will be preserved across prot_call(), unless the C
- * function explicitly overwrites values in rm_regs. Interrupt status
+ * function explicitly overwrites values in ix86. Interrupt status
* will also be preserved. Gate A20 will be enabled.
*
* The protected-mode code may install librm to a new location. If it
@@ -495,12 +495,12 @@ p2r_ljmp:
* lcall $LIBRM_SEGMENT, $prot_call
* addw $4, %sp
* to call in to the C function
- * void pxe_api_call ( struct real_mode_regs *rm_regs );
+ * void pxe_api_call ( struct i386_all_regs *ix86 );
****************************************************************************
*/
-#define PC_OFFSET_RM_REGS ( 0 )
-#define PC_OFFSET_RETADDR ( PC_OFFSET_RM_REGS + SIZEOF_REAL_MODE_REGS )
+#define PC_OFFSET_IX86 ( 0 )
+#define PC_OFFSET_RETADDR ( PC_OFFSET_IX86 + SIZEOF_I386_ALL_REGS )
#define PC_OFFSET_FUNCTION ( PC_OFFSET_RETADDR + 4 )
.code16
@@ -534,14 +534,14 @@ EXPORT(prot_call):
call real_to_prot
.code32
- /* Copy rm_regs from RM stack to PM stack */
- movl $SIZEOF_REAL_MODE_REGS, %ecx
+ /* Copy ix86 from RM stack to PM stack */
+ movl $SIZEOF_I386_ALL_REGS, %ecx
subl %ecx, %esp
movl %esp, %edi
pushl %esi
cld
rep movsb
- popl %edi /* %edi = phys addr of RM copy of rm_regs */
+ popl %edi /* %edi = phys addr of RM copy of ix86 */
/* Switch to virtual addresses. */
call 1f
@@ -555,7 +555,7 @@ EXPORT(prot_call):
popl %eax /* discard */
popal
- /* Push &rm_regs on the stack, and call function */
+ /* Push &ix86 on the stack, and call function */
pushl %esp
call *%ebx
popl %eax /* discard */
@@ -564,16 +564,16 @@ EXPORT(prot_call):
lcall $VIRTUAL_CS, $_virt_to_phys
popl %eax /* discard */
- /* Copy rm_regs from PM stack to RM stack, and remove rm_regs
+ /* Copy ix86 from PM stack to RM stack, and remove ix86
* from PM stack. (%edi still contains physical address of
- * rm_regs on RM stack from earlier, since C code preserves
+ * ix86 on RM stack from earlier, since C code preserves
* %edi).
*/
movl %esp, %esi
- movl $SIZEOF_REAL_MODE_REGS, %ecx
+ movl $SIZEOF_I386_ALL_REGS, %ecx
cld
rep movsb
- movl %esi, %esp /* remove rm_regs from PM stack */
+ movl %esi, %esp /* remove ix86 from PM stack */
/* Obtain physical base address of installed copy of librm in
* %ebx. (It's possible that this *isn't* the physical base
diff --git a/src/arch/i386/transitions/librm_mgmt.c b/src/arch/i386/transitions/librm_mgmt.c
index ffd55ff61..956408f54 100644
--- a/src/arch/i386/transitions/librm_mgmt.c
+++ b/src/arch/i386/transitions/librm_mgmt.c
@@ -139,7 +139,7 @@ POST_RELOC_FN ( POST_RELOC_LIBRM, librm_post_reloc );
* pointer to this new librm's entry point via es:di.
*
*/
-void initialise_via_librm ( struct i386_all_regs *regs ) {
+void initialise_via_librm ( struct i386_all_regs *ix86 ) {
/* Hand off to initialise() */
initialise ();
@@ -147,7 +147,7 @@ void initialise_via_librm ( struct i386_all_regs *regs ) {
* already set up by setup16, so all we need to do is point
* es:0000 to the start of the new librm.
*/
- regs->es = librm_base >> 4;
+ ix86->segs.es = librm_base >> 4;
}
/*
diff --git a/src/arch/ia64/core/efi.c b/src/arch/ia64/core/efi.c
index 97e585fc8..2da768557 100644
--- a/src/arch/ia64/core/efi.c
+++ b/src/arch/ia64/core/efi.c
@@ -898,7 +898,7 @@ struct Elf_Bhdr *prepare_boot_params(void *header)
notes.nf1.n_descsz = sizeof(notes.nf1_bootp_data);
notes.nf1.n_type = EB_BOOTP_DATA;
CP(notes.nf1_name, EB_PARAM_NOTE);
- notes.nf1_bootp_data = virt_to_phys(BOOTP_DATA_ADDR);
+ notes.nf1_bootp_data = virt_to_phys(&bootp_data);
notes.nf2.n_namesz = sizeof(EB_PARAM_NOTE);
notes.nf2.n_descsz = sizeof(notes.nf2_header);
diff --git a/src/arch/ia64/include/stdint.h b/src/arch/ia64/include/stdint.h
index 2f9c592c3..8d8270be8 100644
--- a/src/arch/ia64/include/stdint.h
+++ b/src/arch/ia64/include/stdint.h
@@ -13,4 +13,16 @@ typedef signed short int16_t;
typedef signed int int32_t;
typedef signed long int64_t;
+typedef signed char s8;
+typedef unsigned char u8;
+
+typedef signed short s16;
+typedef unsigned short u16;
+
+typedef signed int s32;
+typedef unsigned int u32;
+
+typedef signed long s64;
+typedef unsigned long u64;
+
#endif /* STDINT_H */
diff --git a/src/config.h b/src/config.h
index d41a403fc..ec4b18019 100644
--- a/src/config.h
+++ b/src/config.h
@@ -75,6 +75,7 @@
#undef DOWNLOAD_PROTO_HTTP /* Hypertext Transfer Protocol */
#undef DOWNLOAD_PROTO_TFTM /* Multicast Trivial File Transfer Protocol */
#undef DOWNLOAD_PROTO_SLAM /* Scalable Local Area Multicast */
+#undef DOWNLOAD_PROTO_FSP /* FSP? */
/* @END general.h */
@@ -91,6 +92,26 @@
/* @BEGIN general.h
*
+ * Image types
+ *
+ * Etherboot supports various image formats. Select whichever ones
+ * you want to use.
+ *
+ */
+#define TAGGED_IMAGE /* NBI image support */
+#undef ELF64_IMAGE /* ELF64 image support */
+#undef ELF_IMAGE /* ELF image support */
+#undef COFF_IMAGE /* COFF image support */
+#undef IMAGE_FREEBSD /* FreeBSD kernel image support */
+#undef IMAGE_MULTIBOOT /* MultiBoot image support */
+#undef AOUT_IMAGE /* a.out image support */
+#undef WINCE_IMAGE /* WinCE image support */
+#undef PXE_IMAGE /* PXE image support */
+
+/* @END general.h */
+
+/* @BEGIN general.h
+ *
* Obscure configuration options
*
* You probably don't need to touch these.
diff --git a/src/core/background.c b/src/core/background.c
new file mode 100644
index 000000000..1cec05a51
--- /dev/null
+++ b/src/core/background.c
@@ -0,0 +1,47 @@
+#include "background.h"
+
+static struct background backgrounds[0] __table_start ( background );
+static struct background backgrounds_end[0] __table_end ( background );
+
+/** @file */
+
+/**
+ * Call send method of all background protocols
+ *
+ * @v timestamp Current time
+ * @ret None -
+ * @err None -
+ *
+ * This calls each background protocol's background::send() method.
+ */
+void background_send ( unsigned long timestamp ) {
+ struct background *background;
+
+ for ( background = backgrounds ; background < backgrounds_end ;
+ background++ ) {
+ if ( background->send )
+ background->send ( timestamp );
+ }
+}
+
+/**
+ * Call process method of all background protocols
+ *
+ * @v timestamp Current time
+ * @v ptype Packet type
+ * @v ip IP header, if present
+ * @ret None -
+ * @err None -
+ *
+ * This calls each background protocol's background::process() method.
+ */
+void background_process ( unsigned long timestamp, unsigned short ptype,
+ struct iphdr *ip ) {
+ struct background *background;
+
+ for ( background = backgrounds ; background < backgrounds_end ;
+ background++ ) {
+ if ( background->process )
+ background->process ( timestamp, ptype, ip );
+ }
+}
diff --git a/src/core/buffer.c b/src/core/buffer.c
index b300d4ece..b1a0464ec 100644
--- a/src/core/buffer.c
+++ b/src/core/buffer.c
@@ -1,35 +1,59 @@
-/*
- * Routines for filling a buffer with data received piecemeal, where
- * the size of the data is not necessarily known in advance.
+
+/** @file
+ *
+ * Buffer internals.
*
- * Some protocols do not provide a mechanism for us to know the size
- * of the file before we happen to receive a particular block
- * (e.g. the final block in an MTFTP transfer). In addition, some
- * protocols (all the multicast protocols plus any TCP-based protocol)
- * can, in theory, provide the data in any order.
+ * A buffer consists of a single, contiguous area of memory, some of
+ * which is "filled" and the remainder of which is "free". The
+ * "filled" and "free" spaces are not necessarily contiguous.
*
- * Rather than requiring each protocol to implement its own equivalent
- * of "dd" to arrange the data into well-sized pieces before handing
- * off to the image loader, we provide these generic buffer functions
- * which assemble a file into a single contiguous block. The whole
- * block is then passed to the image loader.
+ * When a buffer is initialised via init_buffer(), it consists of a
+ * single free space. As data is added to the buffer via
+ * fill_buffer(), this free space decreases and can become fragmented.
*
+ * Each free block within a buffer starts with a "tail byte". If the
+ * tail byte is non-zero, this indicates that the free block is the
+ * tail of the buffer, i.e. occupies all the remaining space up to the
+ * end of the buffer. When the tail byte is non-zero, it indicates
+ * that a descriptor (a @c struct @c buffer_free_block) follows the
+ * tail byte. The descriptor describes the size of the free block and
+ * the address of the next free block.
*
+ * We cannot simply always start a free block with a descriptor,
+ * because it is conceivable that we will, at some point, encounter a
+ * situation in which the final free block of a buffer is too small to
+ * contain a descriptor. Consider a protocol with a blocksize of 512
+ * downloading a 1025-byte file into a 1025-byte buffer. Suppose that
+ * the first two blocks are received; we have now filled 1024 of the
+ * 1025 bytes in the buffer, and our only free block consists of the
+ * 1025th byte. Using a "tail byte" solves this problem.
+ *
+ *
* Note that the rather convoluted way of manipulating the buffer
* descriptors (using copy_{to,from}_phys rather than straightforward
* pointers) is needed to cope with operation as a PXE stack, when we
* may be running in real mode or 16-bit protected mode, and therefore
- * cannot directly access arbitrary areas of memory.
+ * cannot directly access arbitrary areas of memory using simple
+ * pointers.
*
*/
#include "stddef.h"
#include "string.h"
#include "io.h"
+#include "errno.h"
#include "buffer.h"
-/*
- * Initialise a buffer
+/**
+ * Initialise a buffer.
+ *
+ * @v buffer The buffer to be initialised
+ * @ret None -
+ * @err None -
+ *
+ * Set @c buffer->start and @c buffer->end before calling init_buffer().
+ * init_buffer() will initialise the buffer to the state of being
+ * empty.
*
*/
void init_buffer ( struct buffer *buffer ) {
@@ -42,77 +66,107 @@ void init_buffer ( struct buffer *buffer ) {
DBG ( "BUFFER [%x,%x) initialised\n", buffer->start, buffer->end );
}
-/*
- * Split a free block
+/**
+ * Move to the next block in the free list
*
- */
-static void split_free_block ( struct buffer_free_block *desc,
- physaddr_t block, physaddr_t split ) {
- /* If split point is before start of block, do nothing */
- if ( split <= block )
- return;
-
- /* If split point is after end of block, do nothing */
- if ( split >= desc->end )
- return;
-
- DBG ( "BUFFER splitting [%x,%x) -> [%x,%x) [%x,%x)\n",
- block, desc->end, block, split, split, desc->end );
-
- /* Create descriptor for new free block */
- copy_to_phys ( split, &desc->tail, sizeof ( desc->tail ) );
- if ( ! desc->tail )
- copy_to_phys ( split, desc, sizeof ( *desc ) );
-
- /* Update descriptor for old free block */
- desc->tail = 0;
- desc->next_free = split;
- desc->end = split;
- copy_to_phys ( block, desc, sizeof ( *desc ) );
-}
-
-/*
- * Mark a free block as used
+ * @v block The current free block
+ * @v buffer The buffer
+ * @ret True Successfully moved to the next free block
+ * @ret False There are no more free blocks
+ * @ret block The next free block
+ * @err None -
*
+ * Move to the next block in the free block list, filling in @c block
+ * with the descriptor for this next block. If the next block is the
+ * tail block, @c block will be filled with the values calculated for
+ * the tail block, otherwise the descriptor will be read from the free
+ * block itself.
+ *
+ * If there are no more free blocks, next_free_block() returns False
+ * and leaves @c block with invalid contents.
+ *
+ * Set <tt> block->next = buffer->start + buffer->fill </tt> for the
+ * first call to next_free_block().
*/
-static inline void unfree_block ( struct buffer *buffer,
- struct buffer_free_block *desc,
- physaddr_t prev_block ) {
- struct buffer_free_block prev_desc;
-
- /* If this is the first block, just update buffer->fill */
- if ( ! prev_block ) {
- DBG ( "BUFFER marking [%x,%x) as used\n",
- buffer->start + buffer->fill, desc->end );
- buffer->fill = desc->next_free - buffer->start;
- return;
- }
+static inline int next_free_block ( struct buffer_free_block *block,
+ struct buffer *buffer ) {
+ /* Move to next block */
+ block->start = block->next;
+
+ /* If at end of buffer, return 0 */
+ if ( block->start >= buffer->end )
+ return 0;
+
+ /* Set up ->next and ->end as for a tail block */
+ block->next = block->end = buffer->end;
+
+ /* Read tail marker from block */
+ copy_from_phys ( &block->tail, block->start, sizeof ( block->tail ) );
- /* Get descriptor for previous block (which cannot be a tail block) */
- copy_from_phys ( &prev_desc, prev_block, sizeof ( prev_desc ) );
+ /* If not a tail block, read whole block descriptor from block */
+ if ( ! block->tail ) {
+ copy_from_phys ( block, block->start, sizeof ( *block ) );
+ }
- DBG ( "BUFFER marking [%x,%x) as used\n",
- prev_desc.next_free, desc->end );
+ return 1;
+}
- /* Modify descriptor for previous block and write it back */
- prev_desc.next_free = desc->next_free;
- copy_to_phys ( prev_block, &prev_desc, sizeof ( prev_desc ) );
+/**
+ * Store a free block descriptor
+ *
+ * @v block The free block descriptor to store
+ * @ret None -
+ * @err None -
+ *
+ * Writes a free block descriptor back to a free block. If the block
+ * is a tail block, only the tail marker will be written, otherwise
+ * the whole block descriptor will be written.
+ */
+static inline void store_free_block ( struct buffer_free_block *block ) {
+ copy_to_phys ( block->start, block,
+ ( block->tail ?
+ sizeof ( block->tail ) : sizeof ( *block ) ) );
}
-/*
- * Write data into a buffer
+/**
+ * Write data into a buffer.
+ *
+ * @v buffer The buffer into which to write the data
+ * @v data The data to be written
+ * @v offset Offset within the buffer at which to write the data
+ * @v len Length of data to be written
+ * @ret True Data was successfully written
+ * @ret False Data was not written
+ * @err ENOMEM Buffer is too small to contain the data
+ *
+ * Writes a block of data into the buffer. The block need not be
+ * aligned to any particular boundary, or be of any particular size,
+ * and it may overlap blocks already in the buffer (i.e. duplicate
+ * calls to fill_buffer() are explicitly permitted).
*
- * It is the caller's responsibility to ensure that the boundaries
- * between data blocks are more than sizeof(struct buffer_free_block)
- * apart. If this condition is not satisfied, data corruption will
- * occur.
+ * @c buffer->fill will be updated to indicate the fill level of the
+ * buffer, i.e. the offset to the first gap within the buffer. If the
+ * filesize is known (e.g. as with the SLAM protocol), you can test
+ * for end-of-file by checking for @c buffer->fill==filesize. If the
+ * filesize is not known, but there is a well-defined end-of-file test
+ * (e.g. as with the TFTP protocol), you can read @c buffer->fill to
+ * determine the final filesize. If blocks are known to be delivered
+ * in a strictly sequential order with no packet loss or duplication,
+ * then you can pass in @c offset==buffer->fill.
+ *
+ * @b NOTE: It is the caller's responsibility to ensure that the
+ * boundaries between data blocks are more than @c sizeof(struct @c
+ * buffer_free_block) apart. If this condition is not satisfied, data
+ * corruption will occur.
+ *
+ * In practice this is not a problem. Callers of fill_buffer() will
+ * be download protocols such as TFTP, and very few protocols have a
+ * block size smaller than @c sizeof(struct @c buffer_free_block).
*
- * Returns 1 for success, 0 for failure (e.g. buffer too small).
*/
int fill_buffer ( struct buffer *buffer, const void *data,
off_t offset, size_t len ) {
- struct buffer_free_block desc;
- physaddr_t block, prev_block;
+ struct buffer_free_block block, before, after;
physaddr_t data_start, data_end;
/* Calculate start and end addresses of data */
@@ -125,41 +179,57 @@ int fill_buffer ( struct buffer *buffer, const void *data,
if ( data_end > buffer->end ) {
DBG ( "BUFFER [%x,%x) too small for data!\n",
buffer->start, buffer->end );
+ errno = ENOMEM;
return 0;
}
- /* Iterate through the buffer's free blocks */
- prev_block = 0;
- block = buffer->start + buffer->fill;
- while ( block < buffer->end ) {
- /* Read block descriptor */
- desc.next_free = buffer->end;
- desc.end = buffer->end;
- copy_from_phys ( &desc.tail, block, sizeof ( desc.tail ) );
- if ( ! desc.tail )
- copy_from_phys ( &desc, block, sizeof ( desc ) );
-
- /* Split block at data start and end markers */
- split_free_block ( &desc, block, data_start );
- split_free_block ( &desc, block, data_end );
-
- /* Block is now either completely contained by or
- * completely outside the data area
- */
- if ( ( block >= data_start ) && ( block < data_end ) ) {
- /* Block is within the data area */
- unfree_block ( buffer, &desc, prev_block );
- copy_to_phys ( block, data + ( block - data_start ),
- desc.end - block );
- } else {
- /* Block is outside the data area */
- prev_block = block;
- }
-
- /* Move to next free block */
- block = desc.next_free;
+ /* Find 'before' and 'after' blocks, if any */
+ before.start = before.end = 0;
+ after.start = after.end = buffer->end;
+ block.next = buffer->start + buffer->fill;
+ while ( next_free_block ( &block, buffer ) ) {
+ if ( ( block.start < data_start ) &&
+ ( block.start >= before.start ) )
+ memcpy ( &before, &block, sizeof ( before ) );
+ if ( ( block.end > data_end ) &&
+ ( block.end <= after.end ) )
+ memcpy ( &after, &block, sizeof ( after ) );
+ }
+
+ /* Truncate 'before' and 'after' blocks around data. */
+ if ( data_start < before.end )
+ before.end = data_start;
+ if ( data_end > after.start )
+ after.start = data_end;
+
+ /* Link 'after' block to 'before' block */
+ before.next = after.start;
+
+ /* Write back 'before' block, if any */
+ if ( before.start ) {
+ before.tail = 0;
+ ASSERT ( ( before.end - before.start ) >=
+ sizeof ( struct buffer_free_block ) );
+ store_free_block ( &before );
+ } else {
+ buffer->fill = before.next - buffer->start;
}
+ /* Write back 'after' block, if any */
+ if ( after.start < buffer->end ) {
+ ASSERT ( after.tail ||
+ ( ( after.end - after.start ) >=
+ sizeof ( struct buffer_free_block ) ) );
+ store_free_block ( &after );
+ }
+
+ DBG ( "BUFFER [%x,%x) before [%x,%x) after [%x,%x)\n",
+ buffer->start, buffer->end, before.start, before.end,
+ after.start, after.end );
+
+ /* Copy data into buffer */
+ copy_to_phys ( data_start, data, len );
+
DBG ( "BUFFER [%x,%x) full up to %x\n",
buffer->start, buffer->end, buffer->start + buffer->fill );
diff --git a/src/core/config.c b/src/core/config.c
index f8683063f..7756c634e 100644
--- a/src/core/config.c
+++ b/src/core/config.c
@@ -74,6 +74,9 @@ void print_config ( void ) {
#ifdef DOWNLOAD_PROTO_TFTP
"TFTP "
#endif
+#ifdef DOWNLOAD_PROTO_FSP
+ "FSP "
+#endif
#ifdef DOWNLOAD_PROTO_NFS
"NFS "
#endif
diff --git a/src/core/console.c b/src/core/console.c
index 2fbf86380..cd3239d6f 100644
--- a/src/core/console.c
+++ b/src/core/console.c
@@ -1,31 +1,24 @@
-/*
- * Central console switch. Various console devices can be selected
- * via the build options CONSOLE_FIRMWARE, CONSOLE_SERIAL etc.
- * config.c picks up on these definitions and drags in the relevant
- * objects. The linker compiles the console_drivers table for us; we
- * simply delegate to each console_driver that we find in the table.
- *
- * Doing it this way allows for changing CONSOLE_XXX without
- * rebuilding anything other than config.o. This is extremely useful
- * for rom-o-matic.
- */
-
#include "stddef.h"
#include "console.h"
-/* FIXME: we need a cleaner way to pick up cpu_nap(). It makes a
- * real-mode call, and so we don't want to use it with LinuxBIOS.
- */
+/** @file */
+
#include "bios.h"
static struct console_driver console_drivers[0] __table_start ( console );
static struct console_driver console_drivers_end[0] __table_end ( console );
-/*****************************************************************************
- * putchar : write a single character to each console
- *****************************************************************************
+/**
+ * Write a single character to each console device.
+ *
+ * @v character Character to be written
+ * @ret None -
+ * @err None -
+ *
+ * The character is written out to all enabled console devices, using
+ * each device's console_driver::putchar() method.
+ *
*/
-
void putchar ( int character ) {
struct console_driver *console;
@@ -40,10 +33,18 @@ void putchar ( int character ) {
}
}
-/*****************************************************************************
- * has_input : check to see if any input is available on any console,
- * and return a pointer to the console device if so
- *****************************************************************************
+/**
+ * Check to see if any input is available on any console.
+ *
+ * @v None -
+ * @ret console Console device that has input available, if any.
+ * @ret NULL No console device has input available.
+ * @err None -
+ *
+ * All enabled console devices are checked once for available input
+ * using each device's console_driver::iskey() method. The first
+ * console device that has available input will be returned, if any.
+ *
*/
static struct console_driver * has_input ( void ) {
struct console_driver *console;
@@ -58,13 +59,30 @@ static struct console_driver * has_input ( void ) {
return NULL;
}
-/*****************************************************************************
- * getchar : read a single character from any console
+/**
+ * Read a single character from any console.
+ *
+ * @v None -
+ * @ret character Character read from a console.
+ * @err None -
+ *
+ * A character will be read from the first enabled console device that
+ * has input available using that console's console_driver::getchar()
+ * method. If no console has input available to be read, this method
+ * will block. To perform a non-blocking read, use something like
+ *
+ * @code
+ *
+ * int key = iskey() ? getchar() : -1;
+ *
+ * @endcode
+ *
+ * The character read will not be echoed back to any console.
+ *
+ * @bug We need a cleaner way to pick up cpu_nap(). It makes a
+ * real-mode call, and so we don't want to use it with LinuxBIOS.
*
- * NOTE : this function does not echo the character, and it does block
- *****************************************************************************
*/
-
int getchar ( void ) {
struct console_driver *console;
int character = 256;
@@ -92,11 +110,20 @@ int getchar ( void ) {
return character;
}
-/*****************************************************************************
- * iskey : check to see if any input is available on any console
- *****************************************************************************
+/** Check for available input on any console.
+ *
+ * @v None -
+ * @ret True Input is available on a console
+ * @ret False Input is not available on any console
+ * @err None -
+ *
+ * All enabled console devices are checked once for available input
+ * using each device's console_driver::iskey() method. If any console
+ * device has input available, this call will return True. If this
+ * call returns True, you can then safely call getchar() without
+ * blocking.
+ *
*/
-
int iskey ( void ) {
return has_input() ? 1 : 0;
}
diff --git a/src/core/elf_loader.c b/src/core/elf_loader.c
index 88a2975ef..85b60e8a3 100644
--- a/src/core/elf_loader.c
+++ b/src/core/elf_loader.c
@@ -199,7 +199,6 @@ static inline os_download_t elf32_probe(unsigned char *data, unsigned int len)
}
printf("(ELF");
elf_freebsd_probe();
- multiboot_probe(data, len);
printf(")... ");
phdr_size = estate.e.elf32.e_phnum * estate.e.elf32.e_phentsize;
if (estate.e.elf32.e_phoff + phdr_size > len) {
@@ -207,7 +206,7 @@ static inline os_download_t elf32_probe(unsigned char *data, unsigned int len)
return dead_download;
}
if (phdr_size > sizeof(estate.p.dummy)) {
- printf("Program header to big\n");
+ printf("Program header too big\n");
return dead_download;
}
memcpy(&estate.p.phdr32, data + estate.e.elf32.e_phoff, phdr_size);
@@ -251,6 +250,7 @@ static inline os_download_t elf32_probe(unsigned char *data, unsigned int len)
}
#if ELF_NOTES
/* Load ELF notes from the image */
+ estate.check_ip_checksum = 0;
for(estate.segment = 0; estate.segment < estate.e.elf32.e_phnum; estate.segment++) {
if (estate.p.phdr32[estate.segment].p_type != PT_NOTE)
continue;
@@ -289,6 +289,7 @@ static inline os_download_t elf32_probe(unsigned char *data, unsigned int len)
estate.loc = 0;
estate.skip = 0;
estate.toread = 0;
+ multiboot_init();
return elf32_download;
}
@@ -516,6 +517,7 @@ static inline os_download_t elf64_probe(unsigned char *data, unsigned int len)
}
#if ELF_NOTES
/* Load ELF notes from the image */
+ estate.check_ip_checksum = 0;
for(estate.segment = 0; estate.segment < estate.e.elf64.e_phnum; estate.segment++) {
if (estate.p.phdr64[estate.segment].p_type != PT_NOTE)
continue;
diff --git a/src/core/errno.c b/src/core/errno.c
new file mode 100644
index 000000000..83c8564bc
--- /dev/null
+++ b/src/core/errno.c
@@ -0,0 +1,61 @@
+#include "etherboot.h"
+#include "errno.h"
+#include "vsprintf.h"
+
+/** @file
+ *
+ * Error codes and descriptions.
+ *
+ * This file provides the global variable #errno and the function
+ * strerror(). These function much like their standard C library
+ * equivalents.
+ *
+ * The error numbers used by Etherboot are a superset of those defined
+ * by the PXE specification version 2.1. See errno.h for a listing of
+ * the error values.
+ *
+ * To save space in ROM images, error string tables are optional. Use
+ * the ERRORMSG_XXX options in config.h to select which error string
+ * tables you want to include. If an error string table is omitted,
+ * strerror() will simply return the text "Error 0x<errno>".
+ *
+ */
+
+/**
+ * Global "last error" number.
+ *
+ * This is valid only when a function has just returned indicating a
+ * failure.
+ *
+ */
+int errno;
+
+static struct errortab errortab_start[0] __table_start(errortab);
+static struct errortab errortab_end[0] __table_end(errortab);
+
+/**
+ * Retrieve string representation of error number.
+ *
+ * @v errno Error number
+ * @ret strerror Pointer to error text
+ *
+ * If the error is not found in the linked-in error tables, generates
+ * a generic "Error 0x<errno>" message.
+ *
+ * The pointer returned by strerror() is valid only until the next
+ * call to strerror().
+ *
+ */
+const char * strerror ( int errno ) {
+ static char *generic_message = "Error 0x0000";
+ struct errortab *errortab;
+
+ for ( errortab = errortab_start ; errortab < errortab_end ;
+ errortab++ ) {
+ if ( errortab->errno == errno )
+ return errortab->text;
+ }
+
+ sprintf ( generic_message + 8, "%hx", errno );
+ return generic_message;
+}
diff --git a/src/core/main.c b/src/core/main.c
index 3a112eee7..35c7bb2c2 100644
--- a/src/core/main.c
+++ b/src/core/main.c
@@ -31,16 +31,14 @@ Literature dealing with the network protocols:
#include <lib.h>
#endif
+/* Linker symbols */
+extern char _bss[], _ebss[];
+
jmp_buf restart_etherboot;
int url_port;
char as_main_program = 1;
-#ifdef IMAGE_FREEBSD
-int freebsd_howto = 0;
-char freebsd_kernel_env[FREEBSD_KERNEL_ENV_SIZE];
-#endif
-
#if 0
static inline unsigned long ask_boot(unsigned *index)
@@ -199,7 +197,7 @@ int main ( void ) {
/* Probe boot device */
if ( ! probe ( &dev ) ) {
/* Device found on bus, but probe failed */
- printf ( "...probe failed\n" );
+ printf ( "...probe failed: %m\n" );
continue;
}
@@ -212,14 +210,14 @@ int main ( void ) {
/* Configure boot device */
if ( ! configure ( &dev ) ) {
/* Configuration (e.g. DHCP) failed */
- printf ( "...configuration failed\n" );
+ printf ( "...configuration failed: %m\n" );
continue;
}
/* Load boot file from the device */
if ( ! autoload ( &dev, &image, &image_context ) ) {
/* Load (e.g. TFTP) failed */
- printf ( "...load failed\n" );
+ printf ( "...load failed: %m\n" );
continue;
}
@@ -233,7 +231,7 @@ int main ( void ) {
/* Boot the image */
if ( ! image->boot ( image_context ) ) {
/* Boot failed */
- printf ( "...boot failed\n" );
+ printf ( "...boot failed: %m\n" );
continue;
}
@@ -279,6 +277,16 @@ static int main_loop(int state)
if (dev->how_probe == PROBE_FAILED) {
state = -1;
}
+ if (state == 1) {
+ /* The bootp reply might have been changed, re-parse. */
+ decode_rfc1533(bootp_data.bootp_reply.bp_vend, 0,
+#ifdef NO_DHCP_SUPPORT
+ BOOTP_VENDOR_LEN + MAX_BOOTP_EXTLEN,
+#else
+ DHCP_OPT_LEN + MAX_BOOTP_EXTLEN,
+#endif /* NO_DHCP_SUPPORT */
+ 1);
+ }
}
}
switch(state) {
diff --git a/src/core/nic.c b/src/core/nic.c
index 3909f5489..be6eb7bc4 100644
--- a/src/core/nic.c
+++ b/src/core/nic.c
@@ -21,13 +21,10 @@ Literature dealing with the network protocols:
#include "resolv.h"
#include "dev.h"
#include "nic.h"
+#include "background.h"
#include "elf.h" /* FOR EM_CURRENT */
struct arptable_t arptable[MAX_ARP];
-#if MULTICAST_LEVEL2
-unsigned long last_igmpv1 = 0;
-struct igmptable_t igmptable[MAX_IGMP];
-#endif
/* Put rom_info in .nocompress section so romprefix.S can write to it */
struct rom_info rom __attribute__ ((section (".text16.nocompress"))) = {0,0};
static unsigned long netmask;
@@ -36,6 +33,14 @@ char *hostname = "";
int hostnamelen = 0;
static uint32_t xid;
unsigned char *end_of_rfc1533 = NULL;
+unsigned char *addparam;
+int addparamlen;
+
+#ifdef IMAGE_FREEBSD
+int freebsd_howto = 0;
+char freebsd_kernel_env[FREEBSD_KERNEL_ENV_SIZE];
+#endif /* IMAGE_FREEBSD */
+
static int vendorext_isvalid;
static const unsigned char vendorext_magic[] = {0xE4,0x45,0x74,0x68}; /* äEth */
static const unsigned char broadcast[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
@@ -264,9 +269,8 @@ static int nic_configure ( struct type_dev *type_dev ) {
#endif /* PXE_EXPORT */
#endif /* ! NO_DHCP_SUPPORT */
printf(", TFTP: %@", arptable[ARP_SERVER].ipaddr.s_addr);
- if (BOOTP_DATA_ADDR->bootp_reply.bp_giaddr.s_addr)
- printf(", Relay: %@",
- BOOTP_DATA_ADDR->bootp_reply.bp_giaddr.s_addr);
+ if (bootp_data.bootp_reply.bp_giaddr.s_addr)
+ printf(", Relay: %@", bootp_data.bootp_reply.bp_giaddr.s_addr);
if (arptable[ARP_GATEWAY].ipaddr.s_addr)
printf(", Gateway %@", arptable[ARP_GATEWAY].ipaddr.s_addr);
if (arptable[ARP_NAMESERVER].ipaddr.s_addr)
@@ -319,6 +323,22 @@ static int nic_load ( struct type_dev *type_dev, struct buffer *buffer ) {
NULL
#endif
: KERNEL_BUF;
+#ifdef ZPXE_SUFFIX_STRIP
+ {
+ int i = 0;
+ while (kernel[i++]);
+ if(i > 5) {
+ if(kernel[i - 6] == '.' &&
+ kernel[i - 5] == 'z' &&
+ kernel[i - 4] == 'p' &&
+ kernel[i - 3] == 'x' &&
+ kernel[i - 2] == 'e') {
+ printf("Trimming .zpxe extension\n");
+ kernel[i - 6] = 0;
+ }
+ }
+ }
+#endif
if ( kernel ) {
return download_url ( kernel, buffer );
} else {
@@ -427,7 +447,6 @@ int ip_transmit(int len, const void *buf)
destip = ip->dest.s_addr;
if (destip == IP_BROADCAST) {
eth_transmit(broadcast, ETH_P_IP, len, buf);
-#ifdef MULTICAST_LEVEL1
} else if ((destip & htonl(MULTICAST_MASK)) == htonl(MULTICAST_NETWORK)) {
unsigned char multicast[6];
unsigned long hdestip;
@@ -439,7 +458,6 @@ int ip_transmit(int len, const void *buf)
multicast[4] = (hdestip >> 8) & 0xff;
multicast[5] = hdestip & 0xff;
eth_transmit(multicast, ETH_P_IP, len, buf);
-#endif
} else {
if (((destip & netmask) !=
(arptable[ARP_CLIENT].ipaddr.s_addr & netmask)) &&
@@ -664,8 +682,8 @@ static int await_bootp(int ival __unused, void *ptr __unused,
#endif /* NO_DHCP_SUPPORT */
netmask = default_netmask();
/* bootpreply->bp_file will be copied to KERNEL_BUF in the memcpy */
- memcpy((char *)BOOTP_DATA_ADDR, (char *)bootpreply, sizeof(struct bootpd_t));
- decode_rfc1533(BOOTP_DATA_ADDR->bootp_reply.bp_vend, 0,
+ memcpy((char *)&bootp_data, (char *)bootpreply, sizeof(struct bootpd_t));
+ decode_rfc1533(bootp_data.bootp_reply.bp_vend, 0,
#ifdef NO_DHCP_SUPPORT
BOOTP_VENDOR_LEN + MAX_BOOTP_EXTLEN,
#else
@@ -740,11 +758,13 @@ static int bootp(void)
remaining_time = rfc2131_sleep_interval(BOOTP_TIMEOUT, retry++);
stop_time = currticks() + remaining_time;
#ifdef NO_DHCP_SUPPORT
- if (await_reply(await_bootp, 0, NULL, timeout))
+ if (await_reply(await_bootp, 0, NULL, remaining_time))
return(1);
#else
while ( remaining_time > 0 ) {
if (await_reply(await_bootp, 0, NULL, remaining_time)){
+ if (arptable[ARP_CLIENT].ipaddr.s_addr)
+ break;
}
remaining_time = stop_time - currticks();
}
@@ -827,140 +847,6 @@ uint16_t tcpudpchksum(struct iphdr *ip)
return checksum;
}
-#ifdef MULTICAST_LEVEL2
-static void send_igmp_reports(unsigned long now)
-{
- int i;
- for(i = 0; i < MAX_IGMP; i++) {
- if (igmptable[i].time && (now >= igmptable[i].time)) {
- struct igmp_ip_t igmp;
- igmp.router_alert[0] = 0x94;
- igmp.router_alert[1] = 0x04;
- igmp.router_alert[2] = 0;
- igmp.router_alert[3] = 0;
- build_ip_hdr(igmptable[i].group.s_addr,
- 1, IP_IGMP, sizeof(igmp.router_alert), sizeof(igmp), &igmp);
- igmp.igmp.type = IGMPv2_REPORT;
- if (last_igmpv1 &&
- (now < last_igmpv1 + IGMPv1_ROUTER_PRESENT_TIMEOUT)) {
- igmp.igmp.type = IGMPv1_REPORT;
- }
- igmp.igmp.response_time = 0;
- igmp.igmp.chksum = 0;
- igmp.igmp.group.s_addr = igmptable[i].group.s_addr;
- igmp.igmp.chksum = ipchksum(&igmp.igmp, sizeof(igmp.igmp));
- ip_transmit(sizeof(igmp), &igmp);
-#ifdef MDEBUG
- printf("Sent IGMP report to: %@\n", igmp.igmp.group.s_addr);
-#endif
- /* Don't send another igmp report until asked */
- igmptable[i].time = 0;
- }
- }
-}
-
-static void process_igmp(struct iphdr *ip, unsigned long now)
-{
- struct igmp *igmp;
- int i;
- unsigned iplen;
- if (!ip || (ip->protocol == IP_IGMP) ||
- (nic.packetlen < sizeof(struct iphdr) + sizeof(struct igmp))) {
- return;
- }
- iplen = (ip->verhdrlen & 0xf)*4;
- igmp = (struct igmp *)&nic.packet[sizeof(struct iphdr)];
- if (ipchksum(igmp, ntohs(ip->len) - iplen) != 0)
- return;
- if ((igmp->type == IGMP_QUERY) &&
- (ip->dest.s_addr == htonl(GROUP_ALL_HOSTS))) {
- unsigned long interval = IGMP_INTERVAL;
- if (igmp->response_time == 0) {
- last_igmpv1 = now;
- } else {
- interval = (igmp->response_time * TICKS_PER_SEC)/10;
- }
-
-#ifdef MDEBUG
- printf("Received IGMP query for: %@\n", igmp->group.s_addr);
-#endif
- for(i = 0; i < MAX_IGMP; i++) {
- uint32_t group = igmptable[i].group.s_addr;
- if ((group == 0) || (group == igmp->group.s_addr)) {
- unsigned long time;
- time = currticks() + rfc1112_sleep_interval(interval, 0);
- if (time < igmptable[i].time) {
- igmptable[i].time = time;
- }
- }
- }
- }
- if (((igmp->type == IGMPv1_REPORT) || (igmp->type == IGMPv2_REPORT)) &&
- (ip->dest.s_addr == igmp->group.s_addr)) {
-#ifdef MDEBUG
- printf("Received IGMP report for: %@\n", igmp->group.s_addr);
-#endif
- for(i = 0; i < MAX_IGMP; i++) {
- if ((igmptable[i].group.s_addr == igmp->group.s_addr) &&
- igmptable[i].time != 0) {
- igmptable[i].time = 0;
- }
- }
- }
-}
-
-void leave_group(int slot)
-{
- /* Be very stupid and always send a leave group message if
- * I have subscribed. Imperfect but it is standards
- * compliant, easy and reliable to implement.
- *
- * The optimal group leave method is to only send leave when,
- * we were the last host to respond to a query on this group,
- * and igmpv1 compatibility is not enabled.
- */
- if (igmptable[slot].group.s_addr) {
- struct igmp_ip_t igmp;
- igmp.router_alert[0] = 0x94;
- igmp.router_alert[1] = 0x04;
- igmp.router_alert[2] = 0;
- igmp.router_alert[3] = 0;
- build_ip_hdr(htonl(GROUP_ALL_HOSTS),
- 1, IP_IGMP, sizeof(igmp.router_alert), sizeof(igmp), &igmp);
- igmp.igmp.type = IGMP_LEAVE;
- igmp.igmp.response_time = 0;
- igmp.igmp.chksum = 0;
- igmp.igmp.group.s_addr = igmptable[slot].group.s_addr;
- igmp.igmp.chksum = ipchksum(&igmp.igmp, sizeof(igmp));
- ip_transmit(sizeof(igmp), &igmp);
-#ifdef MDEBUG
- printf("Sent IGMP leave for: %@\n", igmp.igmp.group.s_addr);
-#endif
- }
- memset(&igmptable[slot], 0, sizeof(igmptable[0]));
-}
-
-void join_group(int slot, unsigned long group)
-{
- /* I have already joined */
- if (igmptable[slot].group.s_addr == group)
- return;
- if (igmptable[slot].group.s_addr) {
- leave_group(slot);
- }
- /* Only join a group if we are given a multicast ip, this way
- * code can be given a non-multicast (broadcast or unicast ip)
- * and still work...
- */
- if ((group & htonl(MULTICAST_MASK)) == htonl(MULTICAST_NETWORK)) {
- igmptable[slot].group.s_addr = group;
- igmptable[slot].time = currticks();
- }
-}
-#else
-#define send_igmp_reports(now) do {} while(0)
-#define process_igmp(ip, now) do {} while(0)
-#endif
#include "proto_eth_slow.c"
@@ -985,8 +871,8 @@ int await_reply(reply_t reply, int ival, void *ptr, long timeout)
*/
for (;;) {
now = currticks();
+ background_send(now);
send_eth_slow_reports(now);
- send_igmp_reports(now);
result = eth_poll(1);
if (result == 0) {
/* We don't have anything */
@@ -1104,8 +990,8 @@ int await_reply(reply_t reply, int ival, void *ptr, long timeout)
#endif /* MDEBUG */
}
}
+ background_process(now, ptype, ip);
process_eth_slow(ptype, now);
- process_igmp(ip, now);
}
return(0);
}
@@ -1168,6 +1054,8 @@ int decode_rfc1533(unsigned char *p, unsigned int block, unsigned int len, int e
#else
vendorext_isvalid = 0;
#endif
+ addparam = NULL;
+ addparamlen = 0;
if (memcmp(p, rfc1533_cookie, 4))
return(0); /* no RFC 1533 header found */
p += 4;
@@ -1178,7 +1066,7 @@ int decode_rfc1533(unsigned char *p, unsigned int block, unsigned int len, int e
return(0); /* no RFC 1533 header found */
p += 4;
len -= 4; }
- if (extend + len <= (unsigned char *)&(BOOTP_DATA_ADDR->bootp_extension[MAX_BOOTP_EXTLEN])) {
+ if (extend + len <= (unsigned char *)&(bootp_data.bootp_extension[MAX_BOOTP_EXTLEN])) {
memcpy(extend, p, len);
extend += len;
} else {
@@ -1235,6 +1123,17 @@ int decode_rfc1533(unsigned char *p, unsigned int block, unsigned int len, int e
p[6] == RFC1533_VENDOR_MAJOR
)
vendorext_isvalid++;
+ else if (c == RFC1533_VENDOR_ADDPARM) {
+ /* This tag intentionally works for BOTH the encapsulated and
+ * non-encapsulated case, since the current menu code (in mknbi)
+ * creates this tag without encapsulation. In the future both the
+ * menu from mknbi and this code should learn about the proper
+ * encapsulation (which will require substantial changes to various
+ * stuff from mknbi, which will break compatibility with older
+ * versions of Etherboot). */
+ addparam = p + 2;
+ addparamlen = *(p + 1);
+ }
else if (NON_ENCAP_OPT c == RFC1533_VENDOR_ETHERBOOT_ENCAP) {
in_encapsulated_options = 1;
decode_rfc1533(p+2, 0, TAG_LEN(p), -1);
@@ -1289,28 +1188,10 @@ RFC2131_SLEEP_INTERVAL - sleep for expotentially longer times (base << exp) +- 1
long rfc2131_sleep_interval(long base, int exp)
{
unsigned long tmo;
-#ifdef BACKOFF_LIMIT
if (exp > BACKOFF_LIMIT)
exp = BACKOFF_LIMIT;
-#endif
tmo = (base << exp) + (TICKS_PER_SEC - (random()/TWO_SECOND_DIVISOR));
return tmo;
}
-#ifdef MULTICAST_LEVEL2
-/**************************************************************************
-RFC1112_SLEEP_INTERVAL - sleep for expotentially longer times, up to (base << exp)
-**************************************************************************/
-long rfc1112_sleep_interval(long base, int exp)
-{
- unsigned long divisor, tmo;
-#ifdef BACKOFF_LIMIT
- if (exp > BACKOFF_LIMIT)
- exp = BACKOFF_LIMIT;
-#endif
- divisor = RAND_MAX/(base << exp);
- tmo = random()/divisor;
- return tmo;
-}
-#endif /* MULTICAST_LEVEL_2 */
diff --git a/src/core/pxe_export.c b/src/core/pxe_export.c
deleted file mode 100644
index 8b8789475..000000000
--- a/src/core/pxe_export.c
+++ /dev/null
@@ -1,1445 +0,0 @@
-/* PXE API interface for Etherboot.
- *
- * Copyright (C) 2004 Michael Brown <mbrown@fensystems.co.uk>.
- *
- * 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.
- */
-
-/* Tags used in this file:
- *
- * FIXME : obvious
- * PXESPEC : question over interpretation of the PXE spec.
- */
-
-#ifdef PXE_EXPORT
-
-#include "etherboot.h"
-#include "pxe.h"
-#include "pxe_export.h"
-#include "pxe_callbacks.h"
-#include "dev.h"
-#include "nic.h"
-#include "pci.h"
-#include "cpu.h"
-#include "timer.h"
-
-#undef DBG
-#if TRACE_PXE
-#define DBG(...) printf ( __VA_ARGS__ )
-#else
-#define DBG(...)
-#endif
-
-/* Not sure why this isn't a globally-used structure within Etherboot.
- * (Because I didn't want to use packed to prevent gcc from aligning
- * source however it liked. Also nstype is a u16, not a uint. - Ken)
- */
-typedef struct {
- char dest[ETH_ALEN];
- char source[ETH_ALEN];
- unsigned int nstype;
-} media_header_t;
-static const char broadcast_mac[] = { 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF };
-
-/* Global pointer to currently installed PXE stack */
-pxe_stack_t *pxe_stack = NULL;
-
-/* Various startup/shutdown routines. The startup/shutdown call
- * sequence is incredibly badly defined in the Intel PXE spec, for
- * example:
- *
- * PXENV_UNDI_INITIALIZE says that the parameters used to initialize
- * the adaptor should be those supplied to the most recent
- * PXENV_UNDI_STARTUP call. PXENV_UNDI_STARTUP takes no parameters.
- *
- * PXENV_UNDI_CLEANUP says that the rest of the API will not be
- * available after making this call. Figure 3-3 ("Early UNDI API
- * usage") shows a call to PXENV_UNDI_CLEANUP being followed by a
- * call to the supposedly now unavailable PXENV_STOP_UNDI.
- *
- * PXENV_UNLOAD_BASE_STACK talks about freeing up the memory
- * occupied by the PXE stack. Figure 4-3 ("PXE IPL") shows a call
- * to PXENV_STOP_UNDI being made after the call to
- * PXENV_UNLOAD_BASE_STACK, by which time the entire PXE stack
- * should have been freed (and, potentially, zeroed).
- *
- * Nothing, anywhere, seems to mention who's responsible for freeing
- * up the base memory allocated for the stack segment. It's not
- * even clear whether or not this is expected to be in free base
- * memory rather than claimed base memory.
- *
- * Consequently, we adopt a rather defensive strategy, designed to
- * work with any conceivable sequence of initialisation or shutdown
- * calls. We have only two things that we care about:
- *
- * 1. Have we hooked INT 1A and INT 15,E820(etc.)?
- * 2. Is the NIC initialised?
- *
- * The NIC should never be initialised without the vectors being
- * hooked, similarly the vectors should never be unhooked with the NIC
- * still initialised. We do, however, want to be able to have the
- * vectors hooked with the NIC shutdown. We therefore have three
- * possible states:
- *
- * 1. Ready to unload: interrupts unhooked, NIC shutdown.
- * 2. Midway: interrupts hooked, NIC shutdown.
- * 3. Fully ready: interrupts hooked, NIC initialised.
- *
- * We provide the three states CAN_UNLOAD, MIDWAY and READY to define
- * these, and the call pxe_ensure_state() to ensure that the stack is
- * in the specified state. All our PXE API call implementations
- * should use this call to ensure that the state is as required for
- * that PXE API call. This enables us to cope with whatever the
- * end-user's interpretation of the PXE spec may be. It even allows
- * for someone calling e.g. PXENV_START_UNDI followed by
- * PXENV_UDP_WRITE, without bothering with any of the intervening
- * calls.
- *
- * pxe_ensure_state() returns 1 for success, 0 for failure. In the
- * event of failure (which can arise from e.g. asking for state READY
- * when we don't know where our NIC is), the error code
- * PXENV_STATUS_UNDI_INVALID_STATE should be returned to the user.
- * The macros ENSURE_XXX() can be used to achieve this without lots of
- * duplicated code.
- */
-
-/* pxe_[un]hook_stack are architecture-specific and provided in
- * pxe_callbacks.c
- */
-
-int pxe_initialise_nic ( void ) {
- if ( pxe_stack->state >= READY ) return 1;
-
-#warning "device probing mechanism has completely changed"
-#if 0
-
- /* Check if NIC is initialised. dev.disable is set to 0
- * when disable() is called, so we use this.
- */
- if ( dev.disable ) {
- /* NIC may have been initialised independently
- * (e.g. when we set up the stack prior to calling the
- * NBP).
- */
- pxe_stack->state = READY;
- return 1;
- }
-
- /* If we already have a NIC defined, reuse that one with
- * PROBE_AWAKE. If one was specifed via PXENV_START_UNDI, try
- * that one first. Otherwise, set PROBE_FIRST.
- */
-
- if ( dev.state.pci.dev.use_specified == 1 ) {
- dev.how_probe = PROBE_NEXT;
- DBG ( " initialising NIC specified via START_UNDI" );
- } else if ( dev.state.pci.dev.driver ) {
- DBG ( " reinitialising NIC" );
- dev.how_probe = PROBE_AWAKE;
- } else {
- DBG ( " probing for any NIC" );
- dev.how_probe = PROBE_FIRST;
- }
-
- /* Call probe routine to bring up the NIC */
- if ( eth_probe ( &dev ) != PROBE_WORKED ) {
- DBG ( " failed" );
- return 0;
- }
-#endif
-
-
- pxe_stack->state = READY;
- return 1;
-}
-
-int pxe_shutdown_nic ( void ) {
- if ( pxe_stack->state <= MIDWAY ) return 1;
-
- eth_irq ( DISABLE );
- disable ( &dev );
- pxe_stack->state = MIDWAY;
- return 1;
-}
-
-int ensure_pxe_state ( pxe_stack_state_t wanted ) {
- int success = 1;
-
- if ( ! pxe_stack ) return 0;
- if ( wanted >= MIDWAY )
- success = success & hook_pxe_stack();
- if ( wanted > MIDWAY ) {
- success = success & pxe_initialise_nic();
- } else {
- success = success & pxe_shutdown_nic();
- }
- if ( wanted < MIDWAY )
- success = success & unhook_pxe_stack();
- return success;
-}
-
-#define ENSURE_CAN_UNLOAD(structure) if ( ! ensure_pxe_state(CAN_UNLOAD) ) { \
- structure->Status = PXENV_STATUS_UNDI_INVALID_STATE; \
- return PXENV_EXIT_FAILURE; }
-#define ENSURE_MIDWAY(structure) if ( ! ensure_pxe_state(MIDWAY) ) { \
- structure->Status = PXENV_STATUS_UNDI_INVALID_STATE; \
- return PXENV_EXIT_FAILURE; }
-#define ENSURE_READY(structure) if ( ! ensure_pxe_state(READY) ) { \
- structure->Status = PXENV_STATUS_UNDI_INVALID_STATE; \
- return PXENV_EXIT_FAILURE; }
-
-/*****************************************************************************
- *
- * Actual PXE API calls
- *
- *****************************************************************************/
-
-/* PXENV_START_UNDI
- *
- * Status: working
- */
-PXENV_EXIT_t pxenv_start_undi ( t_PXENV_START_UNDI *start_undi ) {
- unsigned char bus, devfn;
-
- DBG ( "PXENV_START_UNDI" );
- ENSURE_MIDWAY(start_undi);
-
- /* Record PCI bus & devfn passed by caller, so we know which
- * NIC they want to use.
- *
- * If they don't match our already-existing NIC structure, set
- * values to ensure that the specified NIC is used at the next
- * call to pxe_intialise_nic().
- */
- bus = ( start_undi->ax >> 8 ) & 0xff;
- devfn = start_undi->ax & 0xff;
-
-#warning "device probing mechanism has completely changed"
-#if 0
- if ( ( pci->dev.driver == NULL ) ||
- ( pci->dev.bus != bus ) || ( pci->dev.devfn != devfn ) ) {
- /* This is quite a bit of a hack and relies on
- * knowledge of the internal operation of Etherboot's
- * probe mechanism.
- */
- DBG ( " set PCI %hhx:%hhx.%hhx",
- bus, PCI_SLOT(devfn), PCI_FUNC(devfn) );
- dev->type = BOOT_NIC;
- dev->to_probe = PROBE_PCI;
- memset ( &dev->state, 0, sizeof(dev->state) );
- pci->advance = 1;
- pci->dev.use_specified = 1;
- pci->dev.bus = bus;
- pci->dev.devfn = devfn;
- }
-#endif
-
- start_undi->Status = PXENV_STATUS_SUCCESS;
- return PXENV_EXIT_SUCCESS;
-}
-
-/* PXENV_UNDI_STARTUP
- *
- * Status: working
- */
-PXENV_EXIT_t pxenv_undi_startup ( t_PXENV_UNDI_STARTUP *undi_startup ) {
- DBG ( "PXENV_UNDI_STARTUP" );
- ENSURE_MIDWAY(undi_startup);
-
- undi_startup->Status = PXENV_STATUS_SUCCESS;
- return PXENV_EXIT_SUCCESS;
-}
-
-/* PXENV_UNDI_CLEANUP
- *
- * Status: working
- */
-PXENV_EXIT_t pxenv_undi_cleanup ( t_PXENV_UNDI_CLEANUP *undi_cleanup ) {
- DBG ( "PXENV_UNDI_CLEANUP" );
- ENSURE_CAN_UNLOAD ( undi_cleanup );
-
- undi_cleanup->Status = PXENV_STATUS_SUCCESS;
- return PXENV_EXIT_SUCCESS;
-}
-
-/* PXENV_UNDI_INITIALIZE
- *
- * Status: working
- */
-PXENV_EXIT_t pxenv_undi_initialize ( t_PXENV_UNDI_INITIALIZE
- *undi_initialize ) {
- DBG ( "PXENV_UNDI_INITIALIZE" );
- ENSURE_MIDWAY ( undi_initialize );
-
- undi_initialize->Status = PXENV_STATUS_SUCCESS;
- return PXENV_EXIT_SUCCESS;
-}
-
-/* PXENV_UNDI_RESET_ADAPTER
- *
- * Status: working
- */
-PXENV_EXIT_t pxenv_undi_reset_adapter ( t_PXENV_UNDI_RESET_ADAPTER
- *undi_reset_adapter ) {
- DBG ( "PXENV_UNDI_RESET_ADAPTER" );
-
- ENSURE_MIDWAY ( undi_reset_adapter );
- ENSURE_READY ( undi_reset_adapter );
-
- undi_reset_adapter->Status = PXENV_STATUS_SUCCESS;
- return PXENV_EXIT_SUCCESS;
-}
-
-/* PXENV_UNDI_SHUTDOWN
- *
- * Status: working
- */
-PXENV_EXIT_t pxenv_undi_shutdown ( t_PXENV_UNDI_SHUTDOWN *undi_shutdown ) {
- DBG ( "PXENV_UNDI_SHUTDOWN" );
- ENSURE_MIDWAY ( undi_shutdown );
-
- undi_shutdown->Status = PXENV_STATUS_SUCCESS;
- return PXENV_EXIT_SUCCESS;
-}
-
-/* PXENV_UNDI_OPEN
- *
- * Status: working
- */
-PXENV_EXIT_t pxenv_undi_open ( t_PXENV_UNDI_OPEN *undi_open ) {
- DBG ( "PXENV_UNDI_OPEN" );
- ENSURE_READY ( undi_open );
-
- /* PXESPEC: This is where we choose to enable interrupts.
- * Can't actually find where we're meant to in the PXE spec,
- * but this should work.
- */
- eth_irq ( ENABLE );
-
- undi_open->Status = PXENV_STATUS_SUCCESS;
- return PXENV_EXIT_SUCCESS;
-}
-
-/* PXENV_UNDI_CLOSE
- *
- * Status: working
- */
-PXENV_EXIT_t pxenv_undi_close ( t_PXENV_UNDI_CLOSE *undi_close ) {
- DBG ( "PXENV_UNDI_CLOSE" );
- ENSURE_MIDWAY ( undi_close );
-
- undi_close->Status = PXENV_STATUS_SUCCESS;
- return PXENV_EXIT_SUCCESS;
-}
-
-/* PXENV_UNDI_TRANSMIT
- *
- * Status: working
- */
-PXENV_EXIT_t pxenv_undi_transmit ( t_PXENV_UNDI_TRANSMIT *undi_transmit ) {
- t_PXENV_UNDI_TBD *tbd;
- const char *dest;
- unsigned int type;
- unsigned int length;
- const char *data;
- media_header_t *media_header;
-
- DBG ( "PXENV_UNDI_TRANSMIT" );
- ENSURE_READY ( undi_transmit );
-
- /* We support only the "immediate" portion of the TBD. Who
- * knows what Intel's "engineers" were smoking when they came
- * up with the array of transmit data blocks...
- */
- tbd = SEGOFF16_TO_PTR ( undi_transmit->TBD );
- if ( tbd->DataBlkCount > 0 ) {
- undi_transmit->Status = PXENV_STATUS_UNDI_INVALID_PARAMETER;
- return PXENV_EXIT_FAILURE;
- }
- data = SEGOFF16_TO_PTR ( tbd->Xmit );
- length = tbd->ImmedLength;
-
- /* If destination is broadcast, we need to supply the MAC address */
- if ( undi_transmit->XmitFlag == XMT_BROADCAST ) {
- dest = broadcast_mac;
- } else {
- dest = SEGOFF16_TO_PTR ( undi_transmit->DestAddr );
- }
-
- /* We can't properly support P_UNKNOWN without rewriting all
- * the driver transmit() methods, so we cheat: if P_UNKNOWN is
- * specified we rip the destination address and type out of
- * the pre-assembled packet, then skip over the header.
- */
- switch ( undi_transmit->Protocol ) {
- case P_IP: type = IP; break;
- case P_ARP: type = ARP; break;
- case P_RARP: type = RARP; break;
- case P_UNKNOWN:
- media_header = (media_header_t*)data;
- dest = media_header->dest;
- type = ntohs ( media_header->nstype );
- data += ETH_HLEN;
- length -= ETH_HLEN;
- break;
- default:
- undi_transmit->Status = PXENV_STATUS_UNDI_INVALID_PARAMETER;
- return PXENV_EXIT_FAILURE;
- }
-
- /* Send the packet */
- eth_transmit ( dest, type, length, data );
-
- undi_transmit->Status = PXENV_STATUS_SUCCESS;
- return PXENV_EXIT_SUCCESS;
-}
-
-/* PXENV_UNDI_SET_MCAST_ADDRESS
- *
- * Status: stub (no PXE multicast support)
- */
-PXENV_EXIT_t pxenv_undi_set_mcast_address ( t_PXENV_UNDI_SET_MCAST_ADDRESS
- *undi_set_mcast_address ) {
- DBG ( "PXENV_UNDI_SET_MCAST_ADDRESS" );
- /* ENSURE_READY ( undi_set_mcast_address ); */
- undi_set_mcast_address->Status = PXENV_STATUS_UNSUPPORTED;
- return PXENV_EXIT_FAILURE;
-}
-
-/* PXENV_UNDI_SET_STATION_ADDRESS
- *
- * Status: working (deliberately incomplete)
- */
-PXENV_EXIT_t pxenv_undi_set_station_address ( t_PXENV_UNDI_SET_STATION_ADDRESS
- *undi_set_station_address ) {
- DBG ( "PXENV_UNDI_SET_STATION_ADDRESS" );
- ENSURE_READY ( undi_set_station_address );
-
- /* We don't offer a facility to set the MAC address; this
- * would require adding extra code to all the Etherboot
- * drivers, for very little benefit. If we're setting it to
- * the current value anyway then return success, otherwise
- * return UNSUPPORTED.
- */
- if ( memcmp ( nic.node_addr,
- &undi_set_station_address->StationAddress,
- ETH_ALEN ) == 0 ) {
- undi_set_station_address->Status = PXENV_STATUS_SUCCESS;
- return PXENV_EXIT_SUCCESS;
- }
- undi_set_station_address->Status = PXENV_STATUS_UNSUPPORTED;
- return PXENV_EXIT_FAILURE;
-}
-
-/* PXENV_UNDI_SET_PACKET_FILTER
- *
- * Status: won't implement (would require driver API changes for no
- * real benefit)
- */
-PXENV_EXIT_t pxenv_undi_set_packet_filter ( t_PXENV_UNDI_SET_PACKET_FILTER
- *undi_set_packet_filter ) {
- DBG ( "PXENV_UNDI_SET_PACKET_FILTER" );
- /* ENSURE_READY ( undi_set_packet_filter ); */
- undi_set_packet_filter->Status = PXENV_STATUS_UNSUPPORTED;
- return PXENV_EXIT_FAILURE;
-}
-
-/* PXENV_UNDI_GET_INFORMATION
- *
- * Status: working
- */
-PXENV_EXIT_t pxenv_undi_get_information ( t_PXENV_UNDI_GET_INFORMATION
- *undi_get_information ) {
- DBG ( "PXENV_UNDI_GET_INFORMATION" );
- ENSURE_READY ( undi_get_information );
-
- undi_get_information->BaseIo = nic.ioaddr;
- undi_get_information->IntNumber = nic.irqno;
- /* Cheat: assume all cards can cope with this */
- undi_get_information->MaxTranUnit = ETH_MAX_MTU;
- /* Cheat: we only ever have Ethernet cards */
- undi_get_information->HwType = ETHER_TYPE;
- undi_get_information->HwAddrLen = ETH_ALEN;
- /* Cheat: assume card is always configured with its permanent
- * node address. This is a valid assumption within Etherboot
- * at the time of writing.
- */
- memcpy ( &undi_get_information->CurrentNodeAddress, nic.node_addr,
- ETH_ALEN );
- memcpy ( &undi_get_information->PermNodeAddress, nic.node_addr,
- ETH_ALEN );
- undi_get_information->ROMAddress = 0;
- /* nic.rom_info->rom_segment; */
- /* We only provide the ability to receive or transmit a single
- * packet at a time. This is a bootloader, not an OS.
- */
- undi_get_information->RxBufCt = 1;
- undi_get_information->TxBufCt = 1;
- undi_get_information->Status = PXENV_STATUS_SUCCESS;
- return PXENV_EXIT_SUCCESS;
-}
-
-/* PXENV_UNDI_GET_STATISTICS
- *
- * Status: won't implement (would require driver API changes for no
- * real benefit)
- */
-PXENV_EXIT_t pxenv_undi_get_statistics ( t_PXENV_UNDI_GET_STATISTICS
- *undi_get_statistics ) {
- DBG ( "PXENV_UNDI_GET_STATISTICS" );
- /* ENSURE_READY ( undi_get_statistics ); */
- undi_get_statistics->Status = PXENV_STATUS_UNSUPPORTED;
- return PXENV_EXIT_FAILURE;
-}
-
-/* PXENV_UNDI_CLEAR_STATISTICS
- *
- * Status: won't implement (would require driver API changes for no
- * real benefit)
- */
-PXENV_EXIT_t pxenv_undi_clear_statistics ( t_PXENV_UNDI_CLEAR_STATISTICS
- *undi_clear_statistics ) {
- DBG ( "PXENV_UNDI_CLEAR_STATISTICS" );
- /* ENSURE_READY ( undi_clear_statistics ); */
- undi_clear_statistics->Status = PXENV_STATUS_UNSUPPORTED;
- return PXENV_EXIT_FAILURE;
-}
-
-/* PXENV_UNDI_INITIATE_DIAGS
- *
- * Status: won't implement (would require driver API changes for no
- * real benefit)
- */
-PXENV_EXIT_t pxenv_undi_initiate_diags ( t_PXENV_UNDI_INITIATE_DIAGS
- *undi_initiate_diags ) {
- DBG ( "PXENV_UNDI_INITIATE_DIAGS" );
- /* ENSURE_READY ( undi_initiate_diags ); */
- undi_initiate_diags->Status = PXENV_STATUS_UNSUPPORTED;
- return PXENV_EXIT_FAILURE;
-}
-
-/* PXENV_UNDI_FORCE_INTERRUPT
- *
- * Status: working
- */
-PXENV_EXIT_t pxenv_undi_force_interrupt ( t_PXENV_UNDI_FORCE_INTERRUPT
- *undi_force_interrupt ) {
- DBG ( "PXENV_UNDI_FORCE_INTERRUPT" );
- ENSURE_READY ( undi_force_interrupt );
-
- eth_irq ( FORCE );
- undi_force_interrupt->Status = PXENV_STATUS_SUCCESS;
- return PXENV_EXIT_SUCCESS;
-}
-
-/* PXENV_UNDI_GET_MCAST_ADDRESS
- *
- * Status: stub (no PXE multicast support)
- */
-PXENV_EXIT_t pxenv_undi_get_mcast_address ( t_PXENV_UNDI_GET_MCAST_ADDRESS
- *undi_get_mcast_address ) {
- DBG ( "PXENV_UNDI_GET_MCAST_ADDRESS" );
- /* ENSURE_READY ( undi_get_mcast_address ); */
- undi_get_mcast_address->Status = PXENV_STATUS_UNSUPPORTED;
- return PXENV_EXIT_FAILURE;
-}
-
-/* PXENV_UNDI_GET_NIC_TYPE
- *
- * Status: working
- */
-PXENV_EXIT_t pxenv_undi_get_nic_type ( t_PXENV_UNDI_GET_NIC_TYPE
- *undi_get_nic_type ) {
-#warning "device probing mechanism has changed completely"
-
-#if 0
- struct dev *dev = &dev;
-
- DBG ( "PXENV_UNDI_GET_NIC_TYPE" );
- ENSURE_READY ( undi_get_nic_type );
-
- if ( dev->to_probe == PROBE_PCI ) {
- struct pci_device *pci = &dev->state.pci.dev;
-
- undi_get_nic_type->NicType = PCI_NIC;
- undi_get_nic_type->info.pci.Vendor_ID = pci->vendor;
- undi_get_nic_type->info.pci.Dev_ID = pci->dev_id;
- undi_get_nic_type->info.pci.Base_Class = pci->class >> 8;
- undi_get_nic_type->info.pci.Sub_Class = pci->class & 0xff;
- undi_get_nic_type->info.pci.BusDevFunc =
- ( pci->bus << 8 ) | pci->devfn;
- /* Cheat: these fields are probably unnecessary, and
- * would require adding extra code to pci.c.
- */
- undi_get_nic_type->info.pci.Prog_Intf = 0;
- undi_get_nic_type->info.pci.Rev = 0;
- undi_get_nic_type->info.pci.SubVendor_ID = 0xffff;
- undi_get_nic_type->info.pci.SubDevice_ID = 0xffff;
- } else if ( dev->to_probe == PROBE_ISA ) {
- /* const struct isa_driver *isa = dev->state.isa.driver; */
-
- undi_get_nic_type->NicType = PnP_NIC;
- /* Don't think anything fills these fields in, and
- * probably no-one will ever be interested in them.
- */
- undi_get_nic_type->info.pnp.EISA_Dev_ID = 0;
- undi_get_nic_type->info.pnp.Base_Class = 0;
- undi_get_nic_type->info.pnp.Sub_Class = 0;
- undi_get_nic_type->info.pnp.Prog_Intf = 0;
- undi_get_nic_type->info.pnp.CardSelNum = 0;
- } else {
- /* PXESPEC: There doesn't seem to be an "unknown type"
- * defined.
- */
- undi_get_nic_type->NicType = 0;
- }
- undi_get_nic_type->Status = PXENV_STATUS_SUCCESS;
- return PXENV_EXIT_SUCCESS;
-
-#endif
-}
-
-/* PXENV_UNDI_GET_IFACE_INFO
- *
- * Status: working
- */
-PXENV_EXIT_t pxenv_undi_get_iface_info ( t_PXENV_UNDI_GET_IFACE_INFO
- *undi_get_iface_info ) {
- DBG ( "PXENV_UNDI_GET_IFACE_INFO" );
- ENSURE_READY ( undi_get_iface_info );
-
- /* Just hand back some info, doesn't really matter what it is.
- * Most PXE stacks seem to take this approach.
- */
- sprintf ( undi_get_iface_info->IfaceType, "Etherboot" );
- undi_get_iface_info->LinkSpeed = 10000000; /* 10 Mbps */
- undi_get_iface_info->ServiceFlags = 0;
- memset ( undi_get_iface_info->Reserved, 0,
- sizeof(undi_get_iface_info->Reserved) );
- undi_get_iface_info->Status = PXENV_STATUS_SUCCESS;
- return PXENV_EXIT_SUCCESS;
-}
-
-/* PXENV_UNDI_ISR
- *
- * Status: working
- */
-PXENV_EXIT_t pxenv_undi_isr ( t_PXENV_UNDI_ISR *undi_isr ) {
- media_header_t *media_header = (media_header_t*)nic.packet;
-
- DBG ( "PXENV_UNDI_ISR" );
- /* We can't call ENSURE_READY, because this could be being
- * called as part of an interrupt service routine. Instead,
- * we should simply die if we're not READY.
- */
- if ( ( pxe_stack == NULL ) || ( pxe_stack->state < READY ) ) {
- undi_isr->Status = PXENV_STATUS_UNDI_INVALID_STATE;
- return PXENV_EXIT_FAILURE;
- }
-
- /* Just in case some idiot actually looks at these fields when
- * we weren't meant to fill them in...
- */
- undi_isr->BufferLength = 0;
- undi_isr->FrameLength = 0;
- undi_isr->FrameHeaderLength = 0;
- undi_isr->ProtType = 0;
- undi_isr->PktType = 0;
-
- switch ( undi_isr->FuncFlag ) {
- case PXENV_UNDI_ISR_IN_START :
- /* Is there a packet waiting? If so, disable
- * interrupts on the NIC and return "it's ours". Do
- * *not* necessarily acknowledge the interrupt; this
- * can happen later when eth_poll(1) is called. As
- * long as the interrupt is masked off so that it
- * doesn't immediately retrigger the 8259A then all
- * should be well.
- */
- DBG ( " START" );
- if ( eth_poll ( 0 ) ) {
- DBG ( " OURS" );
- eth_irq ( DISABLE );
- undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_OURS;
- } else {
- DBG ( " NOT_OURS" );
- undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_NOT_OURS;
- }
- break;
- case PXENV_UNDI_ISR_IN_PROCESS :
- /* Call poll(), return packet. If no packet, return "done".
- */
- DBG ( " PROCESS" );
- if ( eth_poll ( 1 ) ) {
- DBG ( " RECEIVE %d", nic.packetlen );
- if ( nic.packetlen > sizeof(pxe_stack->packet) ) {
- /* Should never happen */
- undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_DONE;
- undi_isr->Status =
- PXENV_STATUS_OUT_OF_RESOURCES;
- return PXENV_EXIT_FAILURE;
- }
- undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_RECEIVE;
- undi_isr->BufferLength = nic.packetlen;
- undi_isr->FrameLength = nic.packetlen;
- undi_isr->FrameHeaderLength = ETH_HLEN;
- memcpy ( pxe_stack->packet, nic.packet, nic.packetlen);
- PTR_TO_SEGOFF16 ( pxe_stack->packet, undi_isr->Frame );
- switch ( ntohs(media_header->nstype) ) {
- case IP : undi_isr->ProtType = P_IP; break;
- case ARP : undi_isr->ProtType = P_ARP; break;
- case RARP : undi_isr->ProtType = P_RARP; break;
- default : undi_isr->ProtType = P_UNKNOWN;
- }
- if ( memcmp ( media_header->dest, broadcast_mac,
- sizeof(broadcast_mac) ) ) {
- undi_isr->PktType = XMT_BROADCAST;
- } else {
- undi_isr->PktType = XMT_DESTADDR;
- }
- break;
- } else {
- /* No break - fall through to IN_GET_NEXT */
- }
- case PXENV_UNDI_ISR_IN_GET_NEXT :
- /* We only ever return one frame at a time */
- DBG ( " GET_NEXT DONE" );
- /* Re-enable interrupts */
- eth_irq ( ENABLE );
- /* Force an interrupt if there's a packet still
- * waiting, since we only handle one packet per
- * interrupt.
- */
- if ( eth_poll ( 0 ) ) {
- DBG ( " (RETRIGGER)" );
- eth_irq ( FORCE );
- }
- undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_DONE;
- break;
- default :
- /* Should never happen */
- undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_DONE;
- undi_isr->Status = PXENV_STATUS_UNDI_INVALID_PARAMETER;
- return PXENV_EXIT_FAILURE;
- }
-
- undi_isr->Status = PXENV_STATUS_SUCCESS;
- return PXENV_EXIT_SUCCESS;
-}
-
-/* PXENV_STOP_UNDI
- *
- * Status: working
- */
-PXENV_EXIT_t pxenv_stop_undi ( t_PXENV_STOP_UNDI *stop_undi ) {
- DBG ( "PXENV_STOP_UNDI" );
-
- if ( ! ensure_pxe_state(CAN_UNLOAD) ) {
- stop_undi->Status = PXENV_STATUS_KEEP_UNDI;
- return PXENV_EXIT_FAILURE;
- }
-
- stop_undi->Status = PXENV_STATUS_SUCCESS;
- return PXENV_EXIT_SUCCESS;
-}
-
-/* PXENV_TFTP_OPEN
- *
- * Status: working
- */
-PXENV_EXIT_t pxenv_tftp_open ( t_PXENV_TFTP_OPEN *tftp_open ) {
- struct sockaddr_in tftp_server;
- struct tftpreq_info_t request;
- struct tftpblk_info_t block;
-
- DBG ( "PXENV_TFTP_OPEN" );
- ENSURE_READY ( tftp_open );
-
- /* Set server address and port */
- tftp_server.sin_addr.s_addr = tftp_open->ServerIPAddress
- ? tftp_open->ServerIPAddress
- : arptable[ARP_SERVER].ipaddr.s_addr;
- tftp_server.sin_port = ntohs ( tftp_open->TFTPPort );
-#ifdef WORK_AROUND_BPBATCH_BUG
- /* Force use of port 69; BpBatch tries to use port 4 for some
- * bizarre reason. */
- tftp_server.sin_port = TFTP_PORT;
-#endif
- /* Ignore gateway address; we can route properly */
- /* Fill in request structure */
- request.server = &tftp_server;
- request.name = tftp_open->FileName;
- request.blksize = tftp_open->PacketSize;
- DBG ( " %@:%d/%s (%d)", tftp_open->ServerIPAddress,
- tftp_open->TFTPPort, request.name, request.blksize );
- if ( !request.blksize ) request.blksize = TFTP_DEFAULTSIZE_PACKET;
- /* Make request and get first packet */
- if ( !tftp_block ( &request, &block ) ) {
- tftp_open->Status = PXENV_STATUS_TFTP_FILE_NOT_FOUND;
- return PXENV_EXIT_FAILURE;
- }
- /* Fill in PacketSize */
- tftp_open->PacketSize = request.blksize;
- /* Store first block for later retrieval by TFTP_READ */
- pxe_stack->tftpdata.magic_cookie = PXE_TFTP_MAGIC_COOKIE;
- pxe_stack->tftpdata.len = block.len;
- pxe_stack->tftpdata.eof = block.eof;
- memcpy ( pxe_stack->tftpdata.data, block.data, block.len );
-
- tftp_open->Status = PXENV_STATUS_SUCCESS;
- return PXENV_EXIT_SUCCESS;
-}
-
-/* PXENV_TFTP_CLOSE
- *
- * Status: working
- */
-PXENV_EXIT_t pxenv_tftp_close ( t_PXENV_TFTP_CLOSE *tftp_close ) {
- DBG ( "PXENV_TFTP_CLOSE" );
- ENSURE_READY ( tftp_close );
- tftp_close->Status = PXENV_STATUS_SUCCESS;
- return PXENV_EXIT_SUCCESS;
-}
-
-/* PXENV_TFTP_READ
- *
- * Status: working
- */
-PXENV_EXIT_t pxenv_tftp_read ( t_PXENV_TFTP_READ *tftp_read ) {
- struct tftpblk_info_t block;
-
- DBG ( "PXENV_TFTP_READ" );
- ENSURE_READY ( tftp_read );
-
- /* Do we have a block pending */
- if ( pxe_stack->tftpdata.magic_cookie == PXE_TFTP_MAGIC_COOKIE ) {
- block.data = pxe_stack->tftpdata.data;
- block.len = pxe_stack->tftpdata.len;
- block.eof = pxe_stack->tftpdata.eof;
- block.block = 1; /* Will be the first block */
- pxe_stack->tftpdata.magic_cookie = 0;
- } else {
- if ( !tftp_block ( NULL, &block ) ) {
- tftp_read->Status = PXENV_STATUS_TFTP_FILE_NOT_FOUND;
- return PXENV_EXIT_FAILURE;
- }
- }
-
- /* Return data */
- tftp_read->PacketNumber = block.block;
- tftp_read->BufferSize = block.len;
- memcpy ( SEGOFF16_TO_PTR(tftp_read->Buffer), block.data, block.len );
- DBG ( " %d to %hx:%hx", block.len, tftp_read->Buffer.segment,
- tftp_read->Buffer.offset );
-
- tftp_read->Status = PXENV_STATUS_SUCCESS;
- return PXENV_EXIT_SUCCESS;
-}
-
-/* PXENV_TFTP_READ_FILE
- *
- * Status: working
- */
-
-int pxe_tftp_read_block ( unsigned char *data, unsigned int block __unused,
- unsigned int len, int eof ) {
- if ( pxe_stack->readfile.buffer ) {
- if ( pxe_stack->readfile.offset + len >=
- pxe_stack->readfile.bufferlen ) return -1;
- memcpy ( pxe_stack->readfile.buffer +
- pxe_stack->readfile.offset, data, len );
- }
- pxe_stack->readfile.offset += len;
- return eof ? 0 : 1;
-}
-
-PXENV_EXIT_t pxenv_tftp_read_file ( t_PXENV_TFTP_READ_FILE *tftp_read_file ) {
- struct sockaddr_in tftp_server;
- int rc;
-
- DBG ( "PXENV_TFTP_READ_FILE %s to [%x,%x)", tftp_read_file->FileName,
- tftp_read_file->Buffer,
- tftp_read_file->Buffer + tftp_read_file->BufferSize );
- ENSURE_READY ( tftp_read_file );
-
- /* inserted by Klaus Wittemeier */
- /* KERNEL_BUF stores the name of the last required file */
- /* This is a fix to make Microsoft Remote Install Services work (RIS) */
- memcpy(KERNEL_BUF, tftp_read_file->FileName, sizeof(KERNEL_BUF));
- /* end of insertion */
-
- /* Set server address and port */
- tftp_server.sin_addr.s_addr = tftp_read_file->ServerIPAddress
- ? tftp_read_file->ServerIPAddress
- : arptable[ARP_SERVER].ipaddr.s_addr;
- tftp_server.sin_port = ntohs ( tftp_read_file->TFTPSrvPort );
-
- pxe_stack->readfile.buffer = phys_to_virt ( tftp_read_file->Buffer );
- pxe_stack->readfile.bufferlen = tftp_read_file->BufferSize;
- pxe_stack->readfile.offset = 0;
-
- rc = tftp ( NULL, &tftp_server, tftp_read_file->FileName,
- pxe_tftp_read_block );
- if ( rc ) {
- tftp_read_file->Status = PXENV_STATUS_FAILURE;
- return PXENV_EXIT_FAILURE;
- }
- tftp_read_file->Status = PXENV_STATUS_SUCCESS;
- return PXENV_EXIT_SUCCESS;
-}
-
-/* PXENV_TFTP_GET_FSIZE
- *
- * Status: working, though ugly (we actually read the whole file,
- * because it's too ugly to make Etherboot request the tsize option
- * and hand it to us).
- */
-PXENV_EXIT_t pxenv_tftp_get_fsize ( t_PXENV_TFTP_GET_FSIZE *tftp_get_fsize ) {
- int rc;
-
- DBG ( "PXENV_TFTP_GET_FSIZE" );
- ENSURE_READY ( tftp_get_fsize );
-
- pxe_stack->readfile.buffer = NULL;
- pxe_stack->readfile.bufferlen = 0;
- pxe_stack->readfile.offset = 0;
-
-#warning "Rewrite pxenv_tftp_get_fsize, please"
- if ( rc ) {
- tftp_get_fsize->FileSize = 0;
- tftp_get_fsize->Status = PXENV_STATUS_FAILURE;
- return PXENV_EXIT_FAILURE;
- }
- tftp_get_fsize->FileSize = pxe_stack->readfile.offset;
- tftp_get_fsize->Status = PXENV_STATUS_SUCCESS;
- return PXENV_EXIT_SUCCESS;
-}
-
-/* PXENV_UDP_OPEN
- *
- * Status: working
- */
-PXENV_EXIT_t pxenv_udp_open ( t_PXENV_UDP_OPEN *udp_open ) {
- DBG ( "PXENV_UDP_OPEN" );
- ENSURE_READY ( udp_open );
-
- if ( udp_open->src_ip &&
- udp_open->src_ip != arptable[ARP_CLIENT].ipaddr.s_addr ) {
- /* Overwrite our IP address */
- DBG ( " with new IP %@", udp_open->src_ip );
- arptable[ARP_CLIENT].ipaddr.s_addr = udp_open->src_ip;
- }
-
- udp_open->Status = PXENV_STATUS_SUCCESS;
- return PXENV_EXIT_SUCCESS;
-}
-
-/* PXENV_UDP_CLOSE
- *
- * Status: working
- */
-PXENV_EXIT_t pxenv_udp_close ( t_PXENV_UDP_CLOSE *udp_close ) {
- DBG ( "PXENV_UDP_CLOSE" );
- ENSURE_READY ( udp_close );
- udp_close->Status = PXENV_STATUS_SUCCESS;
- return PXENV_EXIT_SUCCESS;
-}
-
-/* PXENV_UDP_READ
- *
- * Status: working
- */
-int await_pxe_udp ( int ival __unused, void *ptr,
- unsigned short ptype __unused,
- struct iphdr *ip, struct udphdr *udp,
- struct tcphdr *tcp __unused ) {
- t_PXENV_UDP_READ *udp_read = (t_PXENV_UDP_READ*)ptr;
- uint16_t d_port;
- size_t size;
-
- /* Ignore non-UDP packets */
- if ( !udp ) {
- DBG ( " non-UDP" );
- return 0;
- }
-
- /* Check dest_ip */
- if ( udp_read->dest_ip && ( udp_read->dest_ip != ip->dest.s_addr ) ) {
- DBG ( " wrong dest IP (got %@, wanted %@)",
- ip->dest.s_addr, udp_read->dest_ip );
- return 0;
- }
-
- /* Check dest_port */
- d_port = ntohs ( udp_read->d_port );
- if ( d_port && ( d_port != ntohs(udp->dest) ) ) {
- DBG ( " wrong dest port (got %d, wanted %d)",
- ntohs(udp->dest), d_port );
- return 0;
- }
-
- /* Copy packet to buffer and fill in information */
- udp_read->src_ip = ip->src.s_addr;
- udp_read->s_port = udp->src; /* Both in network order */
- size = ntohs(udp->len) - sizeof(*udp);
- /* Workaround: NTLDR expects us to fill these in, even though
- * PXESPEC clearly defines them as input parameters.
- */
- udp_read->dest_ip = ip->dest.s_addr;
- udp_read->d_port = udp->dest;
- DBG ( " %@:%d->%@:%d (%d)",
- udp_read->src_ip, ntohs(udp_read->s_port),
- udp_read->dest_ip, ntohs(udp_read->d_port), size );
- if ( udp_read->buffer_size < size ) {
- /* PXESPEC: what error code should we actually return? */
- DBG ( " buffer too small (%d)", udp_read->buffer_size );
- udp_read->Status = PXENV_STATUS_OUT_OF_RESOURCES;
- return 0;
- }
- memcpy ( SEGOFF16_TO_PTR ( udp_read->buffer ), &udp->payload, size );
- udp_read->buffer_size = size;
-
- return 1;
-}
-
-PXENV_EXIT_t pxenv_udp_read ( t_PXENV_UDP_READ *udp_read ) {
- DBG ( "PXENV_UDP_READ" );
- ENSURE_READY ( udp_read );
-
- /* Use await_reply with a timeout of zero */
- /* Allow await_reply to change Status if necessary */
- udp_read->Status = PXENV_STATUS_FAILURE;
- if ( ! await_reply ( await_pxe_udp, 0, udp_read, 0 ) ) {
- return PXENV_EXIT_FAILURE;
- }
-
- udp_read->Status = PXENV_STATUS_SUCCESS;
- return PXENV_EXIT_SUCCESS;
-}
-
-/* PXENV_UDP_WRITE
- *
- * Status: working
- */
-PXENV_EXIT_t pxenv_udp_write ( t_PXENV_UDP_WRITE *udp_write ) {
- uint16_t src_port;
- uint16_t dst_port;
- struct udppacket *packet = (struct udppacket *)nic.packet;
- int packet_size;
-
- DBG ( "PXENV_UDP_WRITE" );
- ENSURE_READY ( udp_write );
-
- /* PXE spec says source port is 2069 if not specified */
- src_port = ntohs(udp_write->src_port);
- if ( src_port == 0 ) src_port = 2069;
- dst_port = ntohs(udp_write->dst_port);
- DBG ( " %d->%@:%d (%d)", src_port, udp_write->ip, dst_port,
- udp_write->buffer_size );
-
- /* FIXME: we ignore the gateway specified, since we're
- * confident of being able to do our own routing. We should
- * probably allow for multiple gateways.
- */
-
- /* Copy payload to packet buffer */
- packet_size = ( (void*)&packet->payload - (void*)packet )
- + udp_write->buffer_size;
- if ( packet_size > ETH_FRAME_LEN ) {
- udp_write->Status = PXENV_STATUS_OUT_OF_RESOURCES;
- return PXENV_EXIT_FAILURE;
- }
- memcpy ( &packet->payload, SEGOFF16_TO_PTR(udp_write->buffer),
- udp_write->buffer_size );
-
- /* Transmit packet */
- if ( ! udp_transmit ( udp_write->ip, src_port, dst_port,
- packet_size, packet ) ) {
- udp_write->Status = PXENV_STATUS_FAILURE;
- return PXENV_EXIT_FAILURE;
- }
-
- udp_write->Status = PXENV_STATUS_SUCCESS;
- return PXENV_EXIT_SUCCESS;
-}
-
-/* PXENV_UNLOAD_STACK
- *
- * Status: working
- */
-PXENV_EXIT_t pxenv_unload_stack ( t_PXENV_UNLOAD_STACK *unload_stack ) {
- int success;
-
- DBG ( "PXENV_UNLOAD_STACK" );
- success = ensure_pxe_state ( CAN_UNLOAD );
-
- /* We need to call cleanup() at some point. The network card
- * has already been disabled by ENSURE_CAN_UNLOAD(), but for
- * the sake of completeness we should call the console_fini()
- * etc. that are part of cleanup().
- *
- * There seems to be a lack of consensus on which is the final
- * PXE API call to make, but it's a fairly safe bet that all
- * the potential shutdown sequences will include a call to
- * PXENV_UNLOAD_STACK at some point, so we may as well do it
- * here.
- */
- cleanup();
-
- if ( ! success ) {
- unload_stack->Status = PXENV_STATUS_KEEP_ALL;
- return PXENV_EXIT_FAILURE;
- }
-
- unload_stack->Status = PXENV_STATUS_SUCCESS;
- return PXENV_EXIT_SUCCESS;
-}
-
-/* PXENV_GET_CACHED_INFO
- *
- * Status: working
- */
-PXENV_EXIT_t pxenv_get_cached_info ( t_PXENV_GET_CACHED_INFO
- *get_cached_info ) {
- BOOTPLAYER *cached_info = &pxe_stack->cached_info;
- DBG ( "PXENV_GET_CACHED_INFO %d", get_cached_info->PacketType );
- ENSURE_READY ( get_cached_info );
-
- /* Fill in cached_info structure in our pxe_stack */
-
- /* I don't think there's actually any way we can be called in
- * the middle of a DHCP request...
- */
- cached_info->opcode = BOOTP_REP;
- /* We only have Ethernet drivers */
- cached_info->Hardware = ETHER_TYPE;
- cached_info->Hardlen = ETH_ALEN;
- /* PXESPEC: "Client sets" says the spec, but who's filling in
- * this structure? It ain't the client.
- */
- cached_info->Gatehops = 0;
- cached_info->ident = 0;
- cached_info->seconds = 0;
- cached_info->Flags = BOOTP_BCAST;
- /* PXESPEC: What do 'Client' and 'Your' IP address refer to? */
- cached_info->cip = arptable[ARP_CLIENT].ipaddr.s_addr;
- cached_info->yip = arptable[ARP_CLIENT].ipaddr.s_addr;
- cached_info->sip = arptable[ARP_SERVER].ipaddr.s_addr;
- /* PXESPEC: Does "GIP" mean "Gateway" or "Relay agent"? */
- cached_info->gip = arptable[ARP_GATEWAY].ipaddr.s_addr;
- memcpy ( cached_info->CAddr, arptable[ARP_CLIENT].node, ETH_ALEN );
- /* Nullify server name */
- cached_info->Sname[0] = '\0';
- memcpy ( cached_info->bootfile, KERNEL_BUF,
- sizeof(cached_info->bootfile) );
- /* Copy DHCP vendor options */
- memcpy ( &cached_info->vendor.d, BOOTP_DATA_ADDR->bootp_reply.bp_vend,
- sizeof(cached_info->vendor.d) );
-
- /* Copy to user-specified buffer, or set pointer to our buffer */
- get_cached_info->BufferLimit = sizeof(*cached_info);
- /* PXESPEC: says to test for Buffer == NULL *and* BufferSize =
- * 0, but what are we supposed to do with a null buffer of
- * non-zero size?!
- */
- if ( IS_NULL_SEGOFF16 ( get_cached_info->Buffer ) ) {
- /* Point back to our buffer */
- PTR_TO_SEGOFF16 ( cached_info, get_cached_info->Buffer );
- get_cached_info->BufferSize = sizeof(*cached_info);
- } else {
- /* Copy to user buffer */
- size_t size = sizeof(*cached_info);
- void *buffer = SEGOFF16_TO_PTR ( get_cached_info->Buffer );
- if ( get_cached_info->BufferSize < size )
- size = get_cached_info->BufferSize;
- DBG ( " to %x", virt_to_phys ( buffer ) );
- memcpy ( buffer, cached_info, size );
- /* PXESPEC: Should we return an error if the user
- * buffer is too small? We do return the actual size
- * of the buffer via BufferLimit, so the user does
- * have a way to detect this already.
- */
- }
-
- get_cached_info->Status = PXENV_STATUS_SUCCESS;
- return PXENV_EXIT_SUCCESS;
-}
-
-/* PXENV_RESTART_TFTP
- *
- * Status: working
- */
-PXENV_EXIT_t pxenv_restart_tftp ( t_PXENV_RESTART_TFTP *restart_tftp ) {
- PXENV_EXIT_t tftp_exit;
-
- DBG ( "PXENV_RESTART_TFTP" );
- ENSURE_READY ( restart_tftp );
-
- /* Words cannot describe the complete mismatch between the PXE
- * specification and any possible version of reality...
- */
- restart_tftp->Buffer = PXE_LOAD_ADDRESS; /* Fixed by spec, apparently */
- restart_tftp->BufferSize = get_free_base_memory() - PXE_LOAD_ADDRESS; /* Near enough */
- DBG ( "(" );
- tftp_exit = pxe_api_call ( PXENV_TFTP_READ_FILE, (t_PXENV_ANY*)restart_tftp );
- DBG ( ")" );
- if ( tftp_exit != PXENV_EXIT_SUCCESS ) return tftp_exit;
-
- /* Fire up the new NBP */
- restart_tftp->Status = xstartpxe();
-
- /* Not sure what "SUCCESS" actually means, since we can only
- * return if the new NBP failed to boot...
- */
- return PXENV_EXIT_SUCCESS;
-}
-
-/* PXENV_START_BASE
- *
- * Status: won't implement (requires major structural changes)
- */
-PXENV_EXIT_t pxenv_start_base ( t_PXENV_START_BASE *start_base ) {
- DBG ( "PXENV_START_BASE" );
- /* ENSURE_READY ( start_base ); */
- start_base->Status = PXENV_STATUS_UNSUPPORTED;
- return PXENV_EXIT_FAILURE;
-}
-
-/* PXENV_STOP_BASE
- *
- * Status: working
- */
-PXENV_EXIT_t pxenv_stop_base ( t_PXENV_STOP_BASE *stop_base ) {
- DBG ( "PXENV_STOP_BASE" );
-
- /* The only time we will be called is when the NBP is trying
- * to shut down the PXE stack. There's nothing we need to do
- * in this call.
- */
-
- stop_base->Status = PXENV_STATUS_SUCCESS;
- return PXENV_EXIT_SUCCESS;
-}
-
-/* PXENV_UNDI_LOADER
- *
- * Status: working
- *
- * NOTE: This is not a genuine PXE API call; the loader has a separate
- * entry point. However, to simplify the mapping of the PXE API to
- * the internal Etherboot API, both are directed through the same
- * interface.
- */
-PXENV_EXIT_t pxenv_undi_loader ( undi_loader_t *loader ) {
- uint32_t loader_phys = virt_to_phys ( loader );
-
- DBG ( "PXENV_UNDI_LOADER" );
-
- /* Set UNDI DS as our real-mode stack */
- use_undi_ds_for_rm_stack ( loader->undi_ds );
-
- /* FIXME: These lines are borrowed from main.c. There should
- * probably be a single initialise() function that does all
- * this, but it's currently split interestingly between main()
- * and main_loop()...
- */
-
-
- /* CHECKME: Our init functions have probably already been
- called by the ROM prefix's call to setup(), haven't
- they? */
-
-
-
- /* We have relocated; the loader pointer is now invalid */
- loader = phys_to_virt ( loader_phys );
-
- /* Install PXE stack to area specified by NBP */
- install_pxe_stack ( VIRTUAL ( loader->undi_cs, 0 ) );
-
- /* Call pxenv_start_undi to set parameters. Why the hell PXE
- * requires these parameters to be provided twice is beyond
- * the wit of any sane man. Don't worry if it fails; the NBP
- * should call PXENV_START_UNDI separately anyway.
- */
- pxenv_start_undi ( &loader->start_undi );
- /* Unhook stack; the loader is not meant to hook int 1a etc,
- * but the call the pxenv_start_undi will cause it to happen.
- */
- ENSURE_CAN_UNLOAD ( loader );
-
- /* Fill in addresses of !PXE and PXENV+ structures */
- PTR_TO_SEGOFF16 ( &pxe_stack->pxe, loader->pxe_ptr );
- PTR_TO_SEGOFF16 ( &pxe_stack->pxenv, loader->pxenv_ptr );
-
- loader->Status = PXENV_STATUS_SUCCESS;
- return PXENV_EXIT_SUCCESS;
-}
-
-/* API call dispatcher
- *
- * Status: complete
- */
-PXENV_EXIT_t pxe_api_call ( int opcode, t_PXENV_ANY *params ) {
- PXENV_EXIT_t ret = PXENV_EXIT_FAILURE;
-
- /* Set default status in case child routine fails to do so */
- params->Status = PXENV_STATUS_FAILURE;
-
- DBG ( "[" );
-
- /* Hand off to relevant API routine */
- switch ( opcode ) {
- case PXENV_START_UNDI:
- ret = pxenv_start_undi ( &params->start_undi );
- break;
- case PXENV_UNDI_STARTUP:
- ret = pxenv_undi_startup ( &params->undi_startup );
- break;
- case PXENV_UNDI_CLEANUP:
- ret = pxenv_undi_cleanup ( &params->undi_cleanup );
- break;
- case PXENV_UNDI_INITIALIZE:
- ret = pxenv_undi_initialize ( &params->undi_initialize );
- break;
- case PXENV_UNDI_RESET_ADAPTER:
- ret = pxenv_undi_reset_adapter ( &params->undi_reset_adapter );
- break;
- case PXENV_UNDI_SHUTDOWN:
- ret = pxenv_undi_shutdown ( &params->undi_shutdown );
- break;
- case PXENV_UNDI_OPEN:
- ret = pxenv_undi_open ( &params->undi_open );
- break;
- case PXENV_UNDI_CLOSE:
- ret = pxenv_undi_close ( &params->undi_close );
- break;
- case PXENV_UNDI_TRANSMIT:
- ret = pxenv_undi_transmit ( &params->undi_transmit );
- break;
- case PXENV_UNDI_SET_MCAST_ADDRESS:
- ret = pxenv_undi_set_mcast_address (
- &params->undi_set_mcast_address );
- break;
- case PXENV_UNDI_SET_STATION_ADDRESS:
- ret = pxenv_undi_set_station_address (
- &params->undi_set_station_address );
- break;
- case PXENV_UNDI_SET_PACKET_FILTER:
- ret = pxenv_undi_set_packet_filter (
- &params->undi_set_packet_filter );
- break;
- case PXENV_UNDI_GET_INFORMATION:
- ret = pxenv_undi_get_information (
- &params->undi_get_information );
- break;
- case PXENV_UNDI_GET_STATISTICS:
- ret = pxenv_undi_get_statistics (
- &params->undi_get_statistics );
- break;
- case PXENV_UNDI_CLEAR_STATISTICS:
- ret = pxenv_undi_clear_statistics (
- &params->undi_clear_statistics );
- break;
- case PXENV_UNDI_INITIATE_DIAGS:
- ret = pxenv_undi_initiate_diags (
- &params->undi_initiate_diags );
- break;
- case PXENV_UNDI_FORCE_INTERRUPT:
- ret = pxenv_undi_force_interrupt (
- &params->undi_force_interrupt );
- break;
- case PXENV_UNDI_GET_MCAST_ADDRESS:
- ret = pxenv_undi_get_mcast_address (
- &params->undi_get_mcast_address );
- break;
- case PXENV_UNDI_GET_NIC_TYPE:
- ret = pxenv_undi_get_nic_type ( &params->undi_get_nic_type );
- break;
- case PXENV_UNDI_GET_IFACE_INFO:
- ret = pxenv_undi_get_iface_info (
- &params->undi_get_iface_info );
- break;
- case PXENV_UNDI_ISR:
- ret = pxenv_undi_isr ( &params->undi_isr );
- break;
- case PXENV_STOP_UNDI:
- ret = pxenv_stop_undi ( &params->stop_undi );
- break;
- case PXENV_TFTP_OPEN:
- ret = pxenv_tftp_open ( &params->tftp_open );
- break;
- case PXENV_TFTP_CLOSE:
- ret = pxenv_tftp_close ( &params->tftp_close );
- break;
- case PXENV_TFTP_READ:
- ret = pxenv_tftp_read ( &params->tftp_read );
- break;
- case PXENV_TFTP_READ_FILE:
- ret = pxenv_tftp_read_file ( &params->tftp_read_file );
- break;
- case PXENV_TFTP_GET_FSIZE:
- ret = pxenv_tftp_get_fsize ( &params->tftp_get_fsize );
- break;
- case PXENV_UDP_OPEN:
- ret = pxenv_udp_open ( &params->udp_open );
- break;
- case PXENV_UDP_CLOSE:
- ret = pxenv_udp_close ( &params->udp_close );
- break;
- case PXENV_UDP_READ:
- ret = pxenv_udp_read ( &params->udp_read );
- break;
- case PXENV_UDP_WRITE:
- ret = pxenv_udp_write ( &params->udp_write );
- break;
- case PXENV_UNLOAD_STACK:
- ret = pxenv_unload_stack ( &params->unload_stack );
- break;
- case PXENV_GET_CACHED_INFO:
- ret = pxenv_get_cached_info ( &params->get_cached_info );
- break;
- case PXENV_RESTART_TFTP:
- ret = pxenv_restart_tftp ( &params->restart_tftp );
- break;
- case PXENV_START_BASE:
- ret = pxenv_start_base ( &params->start_base );
- break;
- case PXENV_STOP_BASE:
- ret = pxenv_stop_base ( &params->stop_base );
- break;
- case PXENV_UNDI_LOADER:
- ret = pxenv_undi_loader ( &params->loader );
- break;
-
- default:
- DBG ( "PXENV_UNKNOWN_%hx", opcode );
- params->Status = PXENV_STATUS_UNSUPPORTED;
- ret = PXENV_EXIT_FAILURE;
- break;
- }
-
- if ( params->Status != PXENV_STATUS_SUCCESS ) {
- DBG ( " %hx", params->Status );
- }
- if ( ret != PXENV_EXIT_SUCCESS ) {
- DBG ( ret == PXENV_EXIT_FAILURE ? " err" : " ??" );
- }
- DBG ( "]" );
-
- return ret;
-}
-
-#endif /* PXE_EXPORT */
diff --git a/src/core/vsprintf.c b/src/core/vsprintf.c
index 414b4509a..83a494a66 100644
--- a/src/core/vsprintf.c
+++ b/src/core/vsprintf.c
@@ -2,6 +2,7 @@
#include "if_ether.h" /* for ETH_ALEN */
#include "limits.h" /* for CHAR_BIT */
#include "console.h"
+#include "errno.h"
#include "vsprintf.h"
#define LONG_SHIFT ((int)((sizeof(unsigned long)*CHAR_BIT) - 4))
@@ -9,29 +10,26 @@
#define SHRT_SHIFT ((int)((sizeof(unsigned short)*CHAR_BIT) - 4))
#define CHAR_SHIFT ((int)((sizeof(unsigned char)*CHAR_BIT) - 4))
-/**************************************************************************
-PRINTF and friends
+/** @file */
- Formats:
- %[#]x - 4 bytes int (8 hex digits, lower case)
- %[#]X - 4 bytes int (8 hex digits, upper case)
- %[#]lx - 8 bytes long (16 hex digits, lower case)
- %[#]lX - 8 bytes long (16 hex digits, upper case)
- %[#]hx - 2 bytes int (4 hex digits, lower case)
- %[#]hX - 2 bytes int (4 hex digits, upper case)
- %[#]hhx - 1 byte int (2 hex digits, lower case)
- %[#]hhX - 1 byte int (2 hex digits, upper case)
- - optional # prefixes 0x or 0X
- %d - decimal int
- %c - char
- %s - string
- %@ - Internet address in ddd.ddd.ddd.ddd notation
- %! - Ethernet address in xx:xx:xx:xx:xx:xx notation
- Note: width specification ignored
-**************************************************************************/
+/**
+ * Write a formatted string to a buffer.
+ *
+ * @v buf Buffer into which to write the string, or NULL
+ * @v fmt Format string
+ * @v args Arguments corresponding to the format string
+ * @ret len Length of string written to buffer (if buf != NULL)
+ * @ret 0 (if buf == NULL)
+ * @err None -
+ *
+ * If #buf==NULL, then the string will be written to the console
+ * directly using putchar().
+ *
+ */
static int vsprintf(char *buf, const char *fmt, va_list args)
{
- char *p, *s;
+ const char *p;
+ char *s;
s = buf;
for ( ; *fmt != '\0'; ++fmt) {
if (*fmt != '%') {
@@ -47,10 +45,12 @@ static int vsprintf(char *buf, const char *fmt, va_list args)
while (*fmt >= '0' && *fmt <= '9')
fmt++;
if (*fmt == 's') {
- for(p = va_arg(args, char *); *p != '\0'; p++)
+ for(p = va_arg(args, char *); *p != '\0'; p++)
buf ? *s++ = *p : putchar(*p);
- }
- else { /* Length of item is bounded */
+ } else if (*fmt == 'm') {
+ for(p = strerror(errno); *p != '\0'; p++)
+ buf ? *s++ = *p : putchar(*p);
+ } else { /* Length of item is bounded */
char tmp[40], *q = tmp;
int alt = 0;
int shift = INT_SHIFT;
@@ -70,7 +70,7 @@ static int vsprintf(char *buf, const char *fmt, va_list args)
fmt++;
}
}
-
+
/*
* Before each format q points to tmp buffer
* After each format q points past end of item
@@ -93,7 +93,7 @@ static int vsprintf(char *buf, const char *fmt, va_list args)
*q++ = "0123456789ABCDEF"[(h >> shift) & 0xF] | ncase;
}
else if (*fmt == 'd') {
- char *r;
+ char *r, *t;
long i;
if (shift > INT_SHIFT) {
i = va_arg(args, long);
@@ -104,17 +104,17 @@ static int vsprintf(char *buf, const char *fmt, va_list args)
*q++ = '-';
i = -i;
}
- p = q; /* save beginning of digits */
+ t = q; /* save beginning of digits */
do {
*q++ = '0' + (i % 10);
i /= 10;
} while (i);
/* reverse digits, stop in middle */
r = q; /* don't alter q */
- while (--r > p) {
+ while (--r > t) {
i = *r;
- *r = *p;
- *p++ = i;
+ *r = *t;
+ *t++ = i;
}
}
else if (*fmt == '@') {
@@ -129,7 +129,7 @@ static int vsprintf(char *buf, const char *fmt, va_list args)
--q;
}
else if (*fmt == '!') {
- char *r;
+ const char *r;
p = va_arg(args, char *);
for (r = p + ETH_ALEN; p < r; ++p)
q += sprintf(q, "%hhX:", *p);
@@ -149,6 +149,20 @@ static int vsprintf(char *buf, const char *fmt, va_list args)
return (s - buf);
}
+/**
+ * Write a formatted string to a buffer.
+ *
+ * @v buf Buffer into which to write the string, or NULL
+ * @v fmt Format string
+ * @v ... Arguments corresponding to the format string
+ * @ret len Length of string written to buffer (if buf != NULL)
+ * @ret 0 (if buf == NULL)
+ * @err None -
+ *
+ * If #buf==NULL, then the string will be written to the console
+ * directly using putchar().
+ *
+ */
int sprintf(char *buf, const char *fmt, ...)
{
va_list args;
@@ -159,11 +173,21 @@ int sprintf(char *buf, const char *fmt, ...)
return i;
}
-void printf(const char *fmt, ...)
+/**
+ * Write a formatted string to the console.
+ *
+ * @v fmt Format string
+ * @v ... Arguments corresponding to the format string
+ * @ret None -
+ * @err None -
+ *
+ */
+int printf(const char *fmt, ...)
{
va_list args;
int i;
va_start(args, fmt);
i=vsprintf(0, fmt, args);
va_end(args);
+ return i;
}
diff --git a/src/doc/build_sys.dox b/src/doc/build_sys.dox
new file mode 100644
index 000000000..9466f6621
--- /dev/null
+++ b/src/doc/build_sys.dox
@@ -0,0 +1,419 @@
+/** @page build_sys Build system
+
+@section overview Overview
+
+Building an Etherboot image consists of three stages:
+
+ -# @ref compilation : Compiling all the source files into object files
+ -# @ref linking : Linking a particular image from selected object files
+ -# @ref finalisation : Producing the final output binary
+
+Though this is a remarkably complex process, it is important to note
+that it all happens automatically. Whatever state your build tree is
+in, you can always type, for example
+
+@code
+
+ make bin/rtl8139.dsk
+
+@endcode
+
+and know that you will get a floppy disk image with an RTL8139 driver
+built from the current sources.
+
+@section compilation Compilation
+
+@subsection comp_overview Overview
+
+Each source file (a @c .c or a @c .S file) is compiled into a @c .o
+file in the @c bin/ directory. Etherboot makes minimal use of
+conditional compilation (see @ref ifdef_harmful), and so you will find
+that all objects get built, even the objects that correspond to
+features that you are not intending to include in your image. For
+example, all network card drivers will be compiled even if you are
+just building a ROM for a 3c509 card. This is a deliberate design
+decision; please do @b not attempt to "fix" the build system to avoid
+doing this.
+
+Source files are defined to be any @c .c or @c .S files found in a
+directory listed in the Makefile variable #SRCDIRS. You therefore do
+@b not need to edit the Makefile just because you have added a new
+source file (although you will need to edit the Makefile if you have
+added a new source directory). To see a list of all source
+directories and source files that the build system currently knows
+about, you can use the commands
+
+@code
+
+ make srcdirs
+ make srcs
+
+@endcode
+
+Rules for compiling @c .c and @c .S files are defined in the Makefile
+variables #RULE_c and #RULE_S. Makefile rules are automatically
+generated for each source file using these rules. The generated rules
+can be found in the @c .d file corresponding to each source file;
+these are located in <tt>bin/deps/</tt>. For example, the rules
+generated for <tt>drivers/net/rtl8139.c</tt> can be found in
+<tt>bin/deps/drivers/net/rtl8139.c.d</tt>. These rules allow you to
+type, for example
+
+@code
+
+ make bin/rtl8139.o
+
+@endcode
+
+and have <tt>rtl8139.o</tt> be built from
+<tt>drivers/net/rtl8139.c</tt> using the generic rule #RULE_c for
+compiling @c .c files.
+
+You can see the full list of object files that will be built using
+
+@code
+
+ make bobjs
+
+@endcode
+
+@subsection comp_ar After compilation
+
+Once all objects have been compiled, they will be collected into a
+build library ("blib") in <tt>bin/blib.a</tt>.
+
+@subsection comp_custom Customising compilation
+
+The Makefile rules for a particular object can be customised to a
+certain extent by defining the Makefile variable CFLAGS_@<object@>.
+For example, if you were to set
+
+@code
+
+ CFLAGS_rtl8139 = -DFOO
+
+@endcode
+
+then <tt>bin/rtl8139.o</tt> would be compiled with the additional
+flags <tt>-DFOO</tt>. To see the flags that will be used when
+compiling a particular object, you can use e.g.
+
+@code
+
+ make bin/rtl8139.flags
+
+@endcode
+
+If you need more flexibility than the CFLAGS_@<object@> mechanism
+provides, then you can exclude source files from the automatic rule
+generation process by listing them in the Makefile variable
+#NON_AUTO_SRCS. The command
+
+@code
+
+ make autosrcs
+
+@endcode
+
+will show you which files are currently part of the automatic rule
+generation process.
+
+@subsection comp_multiobj Multiple objects
+
+A single source file can be used to generate multiple object files.
+This is used, for example, to generate the decompressing and the
+non-decompressing prefixes from the same source files.
+
+By default, a single object will be built from each source file. To
+override the list of objects for a source file, you can define the
+Makefile variable OBJS_@<object@>. For example, the
+<tt>arch/i386/prefix/dskprefix.S</tt> source file is built into two
+objects, <tt>bin/dskprefix.o</tt> and <tt>zdskprefix.o</tt> by
+defining the Makefile variable
+
+@code
+
+ OBJS_dskprefix = dskprefix zdskprefix
+
+@endcode
+
+Since there would be little point in building two identical objects,
+customised compilation flags (see @ref comp_custom) are defined as
+
+@code
+
+ CFLAGS_zdskprefix = -DCOMPRESS
+
+@endcode
+
+Thus, <tt>arch/i386/prefix/dskprefix.S</tt> is built into @c
+dskprefix.o using the normal set of flags, and into @c zdskprefix.o
+using the normal set of flags plus <tt>-DCOMPRESS</tt>.
+
+@subsection comp_debug Special debugging targets
+
+In addition to the basic rules #RULE_c and #RULE_S for compiling
+source files into object files, there are various other rules that can
+be useful for debugging.
+
+@subsubsection comp_debug_c_to_c Preprocessed C
+
+You can see the results of preprocessing a @c .c file (including the
+per-object flags defined via CFLAGS_@<object@> if applicable) using
+e.g.
+
+@code
+
+ make bin/rtl8139.c
+
+@endcode
+
+and examining the resulting file (<tt>bin/rtl8139.c</tt> in this
+case).
+
+@subsubsection comp_debug_x_to_s Assembler
+
+You can see the results of assembling a @c .c file, or of
+preprocessing a @c .S file, using e.g.
+
+@code
+
+ make bin/rtl8139.s
+ make bin/zdskprefix.s
+
+@endcode
+
+@subsubsection comp_debug_dbg Debugging-enabled targets
+
+You can build targets with debug messages (DBG()) enabled using e.g.
+
+@code
+
+ make bin/rtl8139.dbg.o
+ make bin/rtl8139.dbg2.o
+
+@endcode
+
+You will probably not need to use these targets directly, since a
+mechanism exists to select debugging levels at build time; see @ref
+debug.
+
+@section linking Linking
+
+@subsection link_overview Overview
+
+Etherboot is designed to be small and extremely customisable. This is
+achieved by linking in only the features that are really wanted in any
+particular build.
+
+There are two places from which the list of desired features is
+obtained:
+
+ -# @ref link_config_h
+ -# @ref link_cmdline
+
+@subsection link_config_h config.h
+
+The config.h file is used to define global build options that are
+likely to apply to all images that you build, such as the console
+types, supported download protocols etc. See the documentation for
+config.h for more details.
+
+@subsection link_cmdline The make command line
+
+When you type a command such as
+
+@code
+
+ make bin/dfe538.zrom
+
+@endcode
+
+it is used to derive the following information:
+
+ - We are building a compressed ROM image
+ - The DFE538 is a PCI NIC, so we need the decompressing PCI ROM prefix
+ - The PCI IDs for the DFE538 are 1186:1300
+ - The DFE538 is an rtl8139-based card, therefore we need the rtl8139 driver
+
+You can see this process in action using the command
+
+@code
+
+ make bin/dfe538.zrom.info
+
+@endcode
+
+which will print
+
+@code
+
+ Elements : dfe538
+ Prefix : zrom
+ Drivers : rtl8139
+ ROM name : dfe538
+ Media : rom
+
+ ROM type : pci
+ PCI vendor : 0x1186
+ PCI device : 0x1300
+
+ LD driver symbols : obj_rtl8139
+ LD prefix symbols : obj_zpciprefix
+ LD ID symbols : pci_vendor_id=0x1186 pci_device_id=0x1300
+
+ LD target flags : -u obj_zpciprefix --defsym check_obj_zpciprefix=obj_zpciprefix -u obj_rtl8139 --defsym check_obj_rtl8139=obj_rtl8139 -u obj_config --defsym check_obj_config=obj_config --defsym pci_vendor_id=0x1186 --defsym pci_device_id=0x1300
+
+@endcode
+
+This should be interpreted as follows:
+
+@code
+
+ Elements : dfe538
+ Prefix : zrom
+
+@endcode
+
+"Elements" is the list of components preceding the first dot in the
+target name. "Prefix" is the component following the first dot in the
+target name. (It's called a "prefix" because the code that makes it a
+@c .zrom (rather than a @c .dsk, @c .zpxe or any other type of target)
+usually ends up at the start of the resulting binary image.)
+
+@code
+
+ Drivers : rtl8139
+
+@endcode
+
+"Drivers" is the list of drivers corresponding to the "Elements".
+Most drivers support several network cards. The PCI_ROM() and
+ISA_ROM() macros are used in the driver source files to list the cards
+that a particular driver can support.
+
+@code
+
+ ROM name : dfe538
+
+@endcode
+
+"ROM name" is the first element in the "Elements" list. It is used to
+select the PCI IDs for a PCI ROM.
+
+@code
+
+ Media : rom
+
+@endcode
+
+"Media" is the "Prefix" minus the leading @c z, if any.
+
+@code
+
+ ROM type : pci
+ PCI vendor : 0x1186
+ PCI device : 0x1300
+
+@endcode
+
+These are derived from the "ROM name" and the PCI_ROM() or ISA_ROM()
+macros in the driver source files.
+
+@code
+
+ LD driver symbols : obj_rtl8139
+ LD prefix symbols : obj_zpciprefix
+
+@endcode
+
+This is the interesting part. At this point, we have established that
+we need the rtl8139 driver (i.e. @c rtl8139.o) and the decompressing
+PCI prefix (i.e. @c zpciprefix.o). Our build system (via the
+compiler.h header file) arranges that every object exports a symbol
+obj_@<object@>; this can be seen by e.g.
+
+@code
+
+ objdump -t bin/rtl8139.o
+
+@endcode
+
+which will show the line
+
+@code
+
+ 00000000 g *ABS* 00000000 obj_rtl8139
+
+@endcode
+
+By instructing the linker that we need the symbols @c obj_rtl8139 and
+@c obj_zpciprefix, we can therefore ensure that these two objects are
+included in our build. (The linker will also include any objects that
+these two objects require, since that's the whole purpose of the
+linker.)
+
+In a similar way, we always instruct the linker that we need the
+symbol @c obj_config, in order to include the object @c config.o. @c
+config.o is used to drag in the objects that were specified via
+config.h; see @ref link_config_h.
+
+@code
+
+ LD target flags : -u obj_zpciprefix --defsym check_obj_zpciprefix=obj_zpciprefix -u obj_rtl8139 --defsym check_obj_rtl8139=obj_rtl8139 -u obj_config --defsym check_obj_config=obj_config --defsym pci_vendor_id=0x1186 --defsym pci_device_id=0x1300
+
+@endcode
+
+These are the flags that we pass to the linker in order to include the
+objects that we want in our build, and to check that they really get
+included. (This latter check is needed to work around what seems to
+be a bug in @c ld).
+
+The linker does its job of linking all the required objects together
+into a coherent build. The best way to see what is happening is to
+look at one of the resulting linker maps; try, for example
+
+@code
+
+ make bin/dfe538.dsk.map
+
+@endcode
+
+The linker map includes, amongst others:
+
+ - A list of which objects are included in the build, and why.
+ - The results of processing the linker script, line-by-line.
+ - A complete symbol table of the resulting build.
+
+It is worth spending time examining the linker map to see how an
+Etherboot image is assembled.
+
+Whatever format is selected, the Etherboot image is built into an ELF
+file, simply because this is the default format used by @c ld.
+
+@section finalisation Finalisation
+
+@subsection final_overview Overview
+
+The ELF file resulting from @ref linking "linking" needs to be
+converted into the final binary image. Usually, this is just a case
+of running
+
+@code
+
+ objcopy -O binary <elf file> <output file>
+
+@endcode
+
+to convert the ELF file into a raw binary image. Certain image
+formats require special additional treatment.
+
+@subsection final_rom ROM images
+
+ROM images must be rounded up to a suitable ROM size (e.g. 16kB or
+32kB), and certain header information such as checksums needs to be
+filled in. This is done by the @c makerom.pl program.
+
+@section debug Debugging-enabled builds
+
+*/
diff --git a/src/doxygen.cfg b/src/doxygen.cfg
new file mode 100644
index 000000000..b0bc4b9ab
--- /dev/null
+++ b/src/doxygen.cfg
@@ -0,0 +1,208 @@
+# Doxyfile 1.2.17
+
+#---------------------------------------------------------------------------
+# General configuration options
+#---------------------------------------------------------------------------
+PROJECT_NAME = Etherboot
+PROJECT_NUMBER =
+OUTPUT_DIRECTORY = @BIN@/doc
+OUTPUT_LANGUAGE = English
+EXTRACT_ALL = NO
+EXTRACT_PRIVATE = YES
+EXTRACT_STATIC = YES
+EXTRACT_LOCAL_CLASSES = YES
+HIDE_UNDOC_MEMBERS = NO
+HIDE_UNDOC_CLASSES = NO
+HIDE_FRIEND_COMPOUNDS = NO
+BRIEF_MEMBER_DESC = YES
+REPEAT_BRIEF = YES
+ALWAYS_DETAILED_SEC = NO
+INLINE_INHERITED_MEMB = NO
+FULL_PATH_NAMES = NO
+STRIP_FROM_PATH =
+INTERNAL_DOCS = YES
+STRIP_CODE_COMMENTS = NO
+CASE_SENSE_NAMES = YES
+SHORT_NAMES = NO
+HIDE_SCOPE_NAMES = NO
+VERBATIM_HEADERS = YES
+SHOW_INCLUDE_FILES = NO
+JAVADOC_AUTOBRIEF = YES
+MULTILINE_CPP_IS_BRIEF = NO
+DETAILS_AT_TOP = YES
+INHERIT_DOCS = YES
+INLINE_INFO = YES
+SORT_MEMBER_DOCS = NO
+DISTRIBUTE_GROUP_DOC = NO
+TAB_SIZE = 8
+GENERATE_TODOLIST = YES
+GENERATE_TESTLIST = YES
+GENERATE_BUGLIST = YES
+GENERATE_DEPRECATEDLIST= YES
+ALIASES = v=@param \
+ ret=@retval \
+ err=@exception
+ENABLED_SECTIONS =
+MAX_INITIALIZER_LINES = 30
+OPTIMIZE_OUTPUT_FOR_C = YES
+OPTIMIZE_OUTPUT_JAVA = NO
+SHOW_USED_FILES = YES
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+QUIET = NO
+WARNINGS = YES
+WARN_IF_UNDOCUMENTED = YES
+WARN_FORMAT =
+WARN_LOGFILE =
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+INPUT = @SRCDIRS@ \
+ include \
+ arch/@ARCH@/include \
+ doc
+FILE_PATTERNS = *.c \
+ *.h \
+ *.S \
+ *.dox
+RECURSIVE = NO
+EXCLUDE =
+EXCLUDE_SYMLINKS = NO
+EXCLUDE_PATTERNS =
+EXAMPLE_PATH =
+EXAMPLE_PATTERNS =
+EXAMPLE_RECURSIVE = NO
+IMAGE_PATH =
+INPUT_FILTER =
+FILTER_SOURCE_FILES = YES
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+SOURCE_BROWSER = YES
+INLINE_SOURCES = NO
+REFERENCED_BY_RELATION = YES
+REFERENCES_RELATION = NO
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+ALPHABETICAL_INDEX = YES
+COLS_IN_ALPHA_INDEX = 5
+IGNORE_PREFIX =
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+GENERATE_HTML = YES
+HTML_OUTPUT =
+HTML_FILE_EXTENSION =
+HTML_HEADER =
+HTML_FOOTER =
+HTML_STYLESHEET =
+HTML_ALIGN_MEMBERS = YES
+GENERATE_HTMLHELP = NO
+CHM_FILE =
+HHC_LOCATION =
+GENERATE_CHI = NO
+BINARY_TOC = NO
+TOC_EXPAND = NO
+DISABLE_INDEX = NO
+ENUM_VALUES_PER_LINE = 4
+GENERATE_TREEVIEW = NO
+TREEVIEW_WIDTH = 250
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+GENERATE_LATEX = YES
+LATEX_OUTPUT =
+LATEX_CMD_NAME = latex
+MAKEINDEX_CMD_NAME = makeindex
+COMPACT_LATEX = YES
+PAPER_TYPE = a4wide
+EXTRA_PACKAGES =
+LATEX_HEADER =
+PDF_HYPERLINKS = NO
+USE_PDFLATEX = NO
+LATEX_BATCHMODE = YES
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+GENERATE_RTF = NO
+RTF_OUTPUT =
+COMPACT_RTF = NO
+RTF_HYPERLINKS = NO
+RTF_STYLESHEET_FILE =
+RTF_EXTENSIONS_FILE =
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+GENERATE_MAN = YES
+MAN_OUTPUT =
+MAN_EXTENSION =
+MAN_LINKS = YES
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+GENERATE_XML = NO
+XML_SCHEMA =
+XML_DTD =
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+GENERATE_AUTOGEN_DEF = NO
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+ENABLE_PREPROCESSING = YES
+MACRO_EXPANSION = YES
+EXPAND_ONLY_PREDEF = YES
+SEARCH_INCLUDES = YES
+INCLUDE_PATH = include \
+ arch/@ARCH@/include
+INCLUDE_FILE_PATTERNS =
+PREDEFINED = DOXYGEN=1
+EXPAND_AS_DEFINED = __attribute__ \
+ PACKED \
+ __unused \
+ __used \
+ __aligned \
+ __table \
+ __table_start \
+ __table_end
+SKIP_FUNCTION_MACROS = YES
+#---------------------------------------------------------------------------
+# Configuration::addtions related to external references
+#---------------------------------------------------------------------------
+TAGFILES =
+GENERATE_TAGFILE =
+ALLEXTERNALS = NO
+EXTERNAL_GROUPS = YES
+PERL_PATH =
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+CLASS_DIAGRAMS = YES
+HIDE_UNDOC_RELATIONS = YES
+HAVE_DOT = NO
+CLASS_GRAPH = YES
+COLLABORATION_GRAPH = YES
+TEMPLATE_RELATIONS = YES
+INCLUDE_GRAPH = YES
+INCLUDED_BY_GRAPH = YES
+GRAPHICAL_HIERARCHY = YES
+DOT_IMAGE_FORMAT = png
+DOT_PATH =
+DOTFILE_DIRS =
+MAX_DOT_GRAPH_WIDTH = 1024
+MAX_DOT_GRAPH_HEIGHT = 1024
+GENERATE_LEGEND = YES
+DOT_CLEANUP = YES
+#---------------------------------------------------------------------------
+# Configuration::addtions related to the search engine
+#---------------------------------------------------------------------------
+SEARCHENGINE = NO
+CGI_NAME =
+CGI_URL =
+DOC_URL =
+DOC_ABSPATH =
+BIN_ABSPATH =
+EXT_DOC_PATHS =
diff --git a/src/drivers/bus/isapnp.c b/src/drivers/bus/isapnp.c
index 6b7c79e45..6476398c4 100644
--- a/src/drivers/bus/isapnp.c
+++ b/src/drivers/bus/isapnp.c
@@ -33,16 +33,18 @@
*
***************************************************************************/
-#include "string.h"
-#include "timer.h"
-#include "io.h"
-#include "console.h"
-#include "isapnp.h"
-
-/*
- * We can have only one ISAPnP bus in a system. Once the read port is
- * known and all cards have been allocated CSNs, there's nothing to be
- * gained by re-scanning for cards.
+/** @file
+ *
+ * ISAPnP bus support
+ *
+ * Etherboot orignally gained ISAPnP support in a very limited way for
+ * the 3c515 NIC. The current implementation is almost a complete
+ * rewrite based on the ISAPnP specification, with passing reference
+ * to the Linux ISAPnP code.
+ *
+ * There can be only one ISAPnP bus in a system. Once the read port
+ * is known and all cards have been allocated CSNs, there's nothing to
+ * be gained by re-scanning for cards.
*
* However, we shouldn't make scanning the ISAPnP bus an INIT_FN(),
* because even ISAPnP probing can still screw up other devices on the
@@ -50,18 +52,30 @@
* an ISAPnP device.
*
* External code (e.g. the ISAPnP ROM prefix) may already know the
- * read port address, in which case it can initialise this value.
- * Note that setting the read port address will prevent further
- * isolation from taking place; you should set the read port address
- * only if you know that devices have already been allocated CSNs.
+ * read port address, in which case it can store it in
+ * #isapnp_read_port. Note that setting the read port address in this
+ * way will prevent further isolation from taking place; you should
+ * set the read port address only if you know that devices have
+ * already been allocated CSNs.
+ *
+ */
+
+#include "string.h"
+#include "timer.h"
+#include "io.h"
+#include "console.h"
+#include "isapnp.h"
+
+/**
+ * ISAPnP Read Port address.
*
*/
uint16_t isapnp_read_port;
-/*
+/**
* Highest assigned CSN.
*
- * Note that *we* do not necessarily assign CSNs; it could be done by
+ * Note that @b we do not necessarily assign CSNs; it could be done by
* the PnP BIOS instead. We therefore set this only when we first try
* to Wake[CSN] a device and find that there's nothing there. Page 16
* (PDF page 22) of the ISAPnP spec states that "Valid Card Select
@@ -116,22 +130,56 @@ static inline uint16_t isapnp_read_word ( uint8_t address ) {
+ isapnp_read_byte ( address + 1 ) );
}
+/** Inform cards of a new read port address */
static inline void isapnp_set_read_port ( void ) {
isapnp_write_byte ( ISAPNP_READPORT, isapnp_read_port >> 2 );
}
+/**
+ * Enter the Isolation state.
+ *
+ * Only cards currently in the Sleep state will respond to this
+ * command.
+ *
+ */
static inline void isapnp_serialisolation ( void ) {
isapnp_write_address ( ISAPNP_SERIALISOLATION );
}
+/**
+ * Enter the Wait for Key state.
+ *
+ * All cards will respond to this command, regardless of their current
+ * state.
+ *
+ */
static inline void isapnp_wait_for_key ( void ) {
isapnp_write_byte ( ISAPNP_CONFIGCONTROL, ISAPNP_CONFIG_WAIT_FOR_KEY );
}
+/**
+ * Reset (i.e. remove) Card Select Number.
+ *
+ * Only cards currently in the Sleep state will respond to this
+ * command.
+ *
+ */
static inline void isapnp_reset_csn ( void ) {
isapnp_write_byte ( ISAPNP_CONFIGCONTROL, ISAPNP_CONFIG_RESET_CSN );
}
+/**
+ * Place a specified card into the Config state.
+ *
+ * @v csn Card Select Number
+ * @ret None -
+ * @err None -
+ *
+ * Only cards currently in the Sleep, Isolation, or Config states will
+ * respond to this command. The card that has the specified CSN will
+ * enter the Config state, all other cards will enter the Sleep state.
+ *
+ */
static inline void isapnp_wake ( uint8_t csn ) {
isapnp_write_byte ( ISAPNP_WAKE, csn );
}
@@ -144,6 +192,19 @@ static inline uint8_t isapnp_read_status ( void ) {
return isapnp_read_byte ( ISAPNP_STATUS );
}
+/**
+ * Assign a Card Select Number to a card, and enter the Config state.
+ *
+ * @v csn Card Select Number
+ * @ret None -
+ * @err None -
+ *
+ * Only cards in the Isolation state will respond to this command.
+ * The isolation protocol is designed so that only one card will
+ * remain in the Isolation state by the time the isolation protocol
+ * completes.
+ *
+ */
static inline void isapnp_write_csn ( uint8_t csn ) {
isapnp_write_byte ( ISAPNP_CARDSELECTNUMBER, csn );
}
@@ -174,12 +235,20 @@ static void isapnp_delay ( void ) {
udelay ( 1000 );
}
-/*
- * The linear feedback shift register as described in Appendix B of
- * the PnP ISA spec. The hardware implementation uses eight D-type
- * latches and two XOR gates. I think this is probably the smallest
- * possible implementation in software. Six instructions when input_bit
- * is a constant 0 (for isapnp_send_key). :)
+/**
+ * Linear feedback shift register.
+ *
+ * @v lfsr Current value of the LFSR
+ * @v input_bit Current input bit to the LFSR
+ * @ret lfsr Next value of the LFSR
+ * @err None -
+ *
+ * This routine implements the linear feedback shift register as
+ * described in Appendix B of the PnP ISA spec. The hardware
+ * implementation uses eight D-type latches and two XOR gates. I
+ * think this is probably the smallest possible implementation in
+ * software. Six instructions when input_bit is a constant 0 (for
+ * isapnp_send_key). :)
*
*/
static inline uint8_t isapnp_lfsr_next ( uint8_t lfsr, int input_bit ) {
@@ -190,8 +259,11 @@ static inline uint8_t isapnp_lfsr_next ( uint8_t lfsr, int input_bit ) {
return lfsr_next;
}
-/*
- * Send the ISAPnP initiation key
+/**
+ * Send the ISAPnP initiation key.
+ *
+ * Sending the key causes all ISAPnP cards that are currently in the
+ * Wait for Key state to transition into the Sleep state.
*
*/
static void isapnp_send_key ( void ) {
@@ -209,8 +281,12 @@ static void isapnp_send_key ( void ) {
}
}
-/*
- * Compute ISAPnP identifier checksum
+/**
+ * Compute ISAPnP identifier checksum
+ *
+ * @v identifier ISAPnP identifier
+ * @ret checksum Expected checksum value
+ * @err None -
*
*/
static uint8_t isapnp_checksum ( struct isapnp_identifier *identifier ) {
@@ -248,9 +324,16 @@ static inline uint8_t isapnp_peek_byte ( void ) {
return 0xff;
}
-/*
- * Read n bytes of resource data from the current location. If buf is
- * NULL, discard data.
+/**
+ * Read resource data.
+ *
+ * @v buf Buffer in which to store data, or NULL
+ * @v bytes Number of bytes to read
+ * @ret None -
+ * @err None -
+ *
+ * Resource data is read from the current location. If #buf is NULL,
+ * the data is discarded.
*
*/
static void isapnp_peek ( uint8_t *buf, size_t bytes ) {
@@ -265,12 +348,19 @@ static void isapnp_peek ( uint8_t *buf, size_t bytes ) {
}
}
-/*
- * Scan through the resource data until we find a particular tag, and
- * read its contents into a buffer.
+/**
+ * Find a tag within the resource data.
*
- * It is the caller's responsibility to ensure that buf is large
- * enough to contain a tag of the requested size.
+ * @v wanted_tag The tag that we're looking for
+ * @v buf Buffer in which to store the tag's contents
+ * @ret True Tag was found
+ * @ret False Tag was not found
+ * @err None -
+ *
+ * Scan through the resource data until we find a particular tag, and
+ * read its contents into a buffer. It is the caller's responsibility
+ * to ensure that #buf is large enough to contain a tag of the
+ * requested size.
*
*/
static int isapnp_find_tag ( uint8_t wanted_tag, uint8_t *buf ) {
@@ -300,10 +390,13 @@ static int isapnp_find_tag ( uint8_t wanted_tag, uint8_t *buf ) {
return 0;
}
-/*
- * Try isolating ISAPnP cards at the current read port. Return the
- * number of ISAPnP cards found. <0 indicates "try a new read port",
- * 0 indicates "definitely no cards".
+/**
+ * Try isolating ISAPnP cards at the current read port.
+ *
+ * @ret \>0 Number of ISAPnP cards found
+ * @ret 0 There are no ISAPnP cards in the system
+ * @ret \<0 A conflict was detected; try a new read port
+ * @err None -
*
* The state diagram on page 18 (PDF page 24) of the PnP ISA spec
* gives the best overview of what happens here.
@@ -429,8 +522,8 @@ static int isapnp_try_isolate ( void ) {
return csn;
}
-/*
- * Isolate all ISAPnP cards, locating a valid read port in the process.
+/**
+ * Find a valid read port and isolate all ISAPnP cards.
*
*/
static void isapnp_isolate ( void ) {
@@ -450,10 +543,17 @@ static void isapnp_isolate ( void ) {
}
}
-/*
- * Increment a bus_loc structure to the next possible ISAPnP location.
- * Leave the structure zeroed and return 0 if there are no more valid
- * locations.
+/**
+ * Increment a #bus_loc structure to the next possible ISAPnP
+ * location.
+ *
+ * @v bus_loc Bus location
+ * @ret True #bus_loc contains a valid ISAPnP location
+ * @ret False There are no more valid ISAPnP locations
+ * @err None -
+ *
+ * If there are no more valid locations, the #bus_loc structure will
+ * be zeroed.
*
*/
static int isapnp_next_location ( struct bus_loc *bus_loc ) {
@@ -471,10 +571,14 @@ static int isapnp_next_location ( struct bus_loc *bus_loc ) {
return ( ++isapnp_loc->logdev ? 1 : ++isapnp_loc->csn );
}
-/*
- * Fill in parameters for an ISAPnP device based on CSN
+/**
+ * Fill in parameters for an ISAPnP device based on CSN.
*
- * Return 1 if device present, 0 otherwise
+ * @v bus_dev Bus device to be filled in
+ * @v bus_loc Bus location as filled in by isapnp_next_location()
+ * @ret True A device is present at this location
+ * @ret False No device is present at this location
+ * @err None -
*
*/
static int isapnp_fill_device ( struct bus_dev *bus_dev,
@@ -566,9 +670,15 @@ static int isapnp_fill_device ( struct bus_dev *bus_dev,
return 1;
}
-/*
+/**
* Test whether or not a driver is capable of driving the device.
*
+ * @v bus_dev Bus device as filled in by isapnp_fill_device()
+ * @v device_driver Device driver
+ * @ret True Driver is capable of driving this device
+ * @ret False Driver is not capable of driving this device
+ * @err None -
+ *
*/
static int isapnp_check_driver ( struct bus_dev *bus_dev,
struct device_driver *device_driver ) {
@@ -598,8 +708,15 @@ static int isapnp_check_driver ( struct bus_dev *bus_dev,
return 0;
}
-/*
- * Describe an ISAPnP device
+/**
+ * Describe an ISAPnP device.
+ *
+ * @v bus_dev Bus device as filled in by isapnp_fill_device()
+ * @ret string Printable string describing the device
+ * @err None -
+ *
+ * The string returned by isapnp_describe_device() is valid only until
+ * the next call to isapnp_describe_device().
*
*/
static char * isapnp_describe_device ( struct bus_dev *bus_dev ) {
@@ -611,8 +728,15 @@ static char * isapnp_describe_device ( struct bus_dev *bus_dev ) {
return isapnp_description;
}
-/*
- * Name an ISAPnP device
+/**
+ * Name an ISAPnP device.
+ *
+ * @v bus_dev Bus device as filled in by isapnp_fill_device()
+ * @ret string Printable string naming the device
+ * @err None -
+ *
+ * The string returned by isapnp_name_device() is valid only until the
+ * next call to isapnp_name_device().
*
*/
static const char * isapnp_name_device ( struct bus_dev *bus_dev ) {
@@ -634,12 +758,17 @@ struct bus_driver isapnp_driver __bus_driver = {
.name_device = isapnp_name_device,
};
-/*
- * Activate or deactivate an ISAPnP device
+/**
+ * Activate or deactivate an ISAPnP device.
+ *
+ * @v isapnp ISAPnP device
+ * @v activation True to enable, False to disable the device
+ * @ret None -
+ * @err None -
*
* This routine simply activates the device in its current
- * configuration. It does not attempt any kind of resource
- * arbitration.
+ * configuration, or deactivates the device. It does not attempt any
+ * kind of resource arbitration.
*
*/
void isapnp_device_activation ( struct isapnp_device *isapnp,
@@ -662,8 +791,17 @@ void isapnp_device_activation ( struct isapnp_device *isapnp,
isapnp->csn, isapnp->logdev );
}
-/*
- * Fill in a nic structure
+/**
+ * Fill in a nic structure.
+ *
+ * @v nic NIC structure to be filled in
+ * @v isapnp ISAPnP device
+ * @ret None -
+ * @err None -
+ *
+ * This fills in generic NIC parameters (e.g. I/O address and IRQ
+ * number) that can be determined directly from the ISAPnP device,
+ * without any driver-specific knowledge.
*
*/
void isapnp_fill_nic ( struct nic *nic, struct isapnp_device *isapnp ) {
diff --git a/src/drivers/bus/pci.c b/src/drivers/bus/pci.c
index 95a76502b..02286b7cf 100644
--- a/src/drivers/bus/pci.c
+++ b/src/drivers/bus/pci.c
@@ -256,11 +256,12 @@ unsigned long pci_bar_start ( struct pci_device *pci, unsigned int index ) {
pci_read_config_dword ( pci, index + 4, &hi );
if ( hi ) {
#if ULONG_MAX > 0xffffffff
- bar = hi;
- bar <<= 32;
+ bar = hi;
+ bar <<= 32;
#else
- printf ( "Unhandled 64bit BAR\n" );
- return -1UL;
+ printf ( "Unhandled 64bit BAR %08x:%08x\n",
+ hi, lo );
+ return -1UL;
#endif
}
}
diff --git a/src/drivers/net/3c515.c b/src/drivers/net/3c515.c
index 7fcc9f0fe..c87495006 100644
--- a/src/drivers/net/3c515.c
+++ b/src/drivers/net/3c515.c
@@ -61,10 +61,6 @@ static void t3c515_wait(unsigned int nticks)
/* TJL definations */
#define HZ 100
-#define u16 unsigned short
-#define u32 unsigned long
-#define s16 signed short
-#define s32 signed long
static int if_port;
static struct corkscrew_private *vp;
/* Brought directly from 3c515.c by Becker */
diff --git a/src/drivers/net/amd8111e.c b/src/drivers/net/amd8111e.c
new file mode 100644
index 000000000..611cbc854
--- /dev/null
+++ b/src/drivers/net/amd8111e.c
@@ -0,0 +1,681 @@
+/* Advanced Micro Devices Inc. AMD8111E Linux Network Driver
+ * Copyright (C) 2004 Advanced Micro Devices
+ * Copyright (C) 2005 Liu Tao <liutao1980@gmail.com> [etherboot port]
+ *
+ * Copyright 2001,2002 Jeff Garzik <jgarzik@mandrakesoft.com> [ 8139cp.c,tg3.c ]
+ * Copyright (C) 2001, 2002 David S. Miller (davem@redhat.com)[ tg3.c]
+ * Copyright 1996-1999 Thomas Bogendoerfer [ pcnet32.c ]
+ * Derived from the lance driver written 1993,1994,1995 by Donald Becker.
+ * Copyright 1993 United States Government as represented by the
+ * Director, National Security Agency.[ pcnet32.c ]
+ * Carsten Langgaard, carstenl@mips.com [ pcnet32.c ]
+ * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved.
+ *
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#include "etherboot.h"
+#include "nic.h"
+#include "mii.h"
+#include "pci.h"
+#include "timer.h"
+#include "string.h"
+#include "stdint.h"
+#include "amd8111e.h"
+
+
+/* driver definitions */
+#define NUM_TX_SLOTS 2
+#define NUM_RX_SLOTS 4
+#define TX_SLOTS_MASK 1
+#define RX_SLOTS_MASK 3
+
+#define TX_BUF_LEN 1536
+#define RX_BUF_LEN 1536
+
+#define TX_PKT_LEN_MAX (ETH_FRAME_LEN - ETH_HLEN)
+#define RX_PKT_LEN_MIN 60
+#define RX_PKT_LEN_MAX ETH_FRAME_LEN
+
+#define TX_TIMEOUT 3000
+#define TX_PROCESS_TIME 10
+#define TX_RETRY (TX_TIMEOUT / TX_PROCESS_TIME)
+
+#define PHY_RW_RETRY 10
+
+
+struct amd8111e_tx_desc {
+ u16 buf_len;
+ u16 tx_flags;
+ u16 tag_ctrl_info;
+ u16 tag_ctrl_cmd;
+ u32 buf_phy_addr;
+ u32 reserved;
+};
+
+struct amd8111e_rx_desc {
+ u32 reserved;
+ u16 msg_len;
+ u16 tag_ctrl_info;
+ u16 buf_len;
+ u16 rx_flags;
+ u32 buf_phy_addr;
+};
+
+struct eth_frame {
+ u8 dst_addr[ETH_ALEN];
+ u8 src_addr[ETH_ALEN];
+ u16 type;
+ u8 data[ETH_FRAME_LEN - ETH_HLEN];
+} __attribute__((packed));
+
+struct amd8111e_priv {
+ struct amd8111e_tx_desc tx_ring[NUM_TX_SLOTS];
+ struct amd8111e_rx_desc rx_ring[NUM_RX_SLOTS];
+ unsigned char tx_buf[NUM_TX_SLOTS][TX_BUF_LEN];
+ unsigned char rx_buf[NUM_RX_SLOTS][RX_BUF_LEN];
+ unsigned long tx_idx, rx_idx;
+ int tx_consistent;
+
+ char opened;
+ char link;
+ char speed;
+ char duplex;
+ int ext_phy_addr;
+ u32 ext_phy_id;
+
+ struct pci_device *pdev;
+ struct nic *nic;
+ void *mmio;
+};
+
+static struct amd8111e_priv amd8111e;
+
+
+/********************************************************
+ * locale functions *
+ ********************************************************/
+static void amd8111e_init_hw_default(struct amd8111e_priv *lp);
+static int amd8111e_start(struct amd8111e_priv *lp);
+static int amd8111e_read_phy(struct amd8111e_priv *lp, int phy_addr, int reg, u32 *val);
+#if 0
+static int amd8111e_write_phy(struct amd8111e_priv *lp, int phy_addr, int reg, u32 val);
+#endif
+static void amd8111e_probe_ext_phy(struct amd8111e_priv *lp);
+static void amd8111e_disable_interrupt(struct amd8111e_priv *lp);
+static void amd8111e_enable_interrupt(struct amd8111e_priv *lp);
+static void amd8111e_force_interrupt(struct amd8111e_priv *lp);
+static int amd8111e_get_mac_address(struct amd8111e_priv *lp);
+static int amd8111e_init_rx_ring(struct amd8111e_priv *lp);
+static int amd8111e_init_tx_ring(struct amd8111e_priv *lp);
+static int amd8111e_wait_tx_ring(struct amd8111e_priv *lp, unsigned int index);
+static void amd8111e_wait_link(struct amd8111e_priv *lp);
+static void amd8111e_poll_link(struct amd8111e_priv *lp);
+static void amd8111e_restart(struct amd8111e_priv *lp);
+
+
+/*
+ * This function clears necessary the device registers.
+ */
+static void amd8111e_init_hw_default(struct amd8111e_priv *lp)
+{
+ unsigned int reg_val;
+ unsigned int logic_filter[2] = {0,};
+ void *mmio = lp->mmio;
+
+ /* stop the chip */
+ writel(RUN, mmio + CMD0);
+
+ /* Clear RCV_RING_BASE_ADDR */
+ writel(0, mmio + RCV_RING_BASE_ADDR0);
+
+ /* Clear XMT_RING_BASE_ADDR */
+ writel(0, mmio + XMT_RING_BASE_ADDR0);
+ writel(0, mmio + XMT_RING_BASE_ADDR1);
+ writel(0, mmio + XMT_RING_BASE_ADDR2);
+ writel(0, mmio + XMT_RING_BASE_ADDR3);
+
+ /* Clear CMD0 */
+ writel(CMD0_CLEAR, mmio + CMD0);
+
+ /* Clear CMD2 */
+ writel(CMD2_CLEAR, mmio + CMD2);
+
+ /* Clear CMD7 */
+ writel(CMD7_CLEAR, mmio + CMD7);
+
+ /* Clear DLY_INT_A and DLY_INT_B */
+ writel(0x0, mmio + DLY_INT_A);
+ writel(0x0, mmio + DLY_INT_B);
+
+ /* Clear FLOW_CONTROL */
+ writel(0x0, mmio + FLOW_CONTROL);
+
+ /* Clear INT0 write 1 to clear register */
+ reg_val = readl(mmio + INT0);
+ writel(reg_val, mmio + INT0);
+
+ /* Clear STVAL */
+ writel(0x0, mmio + STVAL);
+
+ /* Clear INTEN0 */
+ writel(INTEN0_CLEAR, mmio + INTEN0);
+
+ /* Clear LADRF */
+ writel(0x0, mmio + LADRF);
+
+ /* Set SRAM_SIZE & SRAM_BOUNDARY registers */
+ writel(0x80010, mmio + SRAM_SIZE);
+
+ /* Clear RCV_RING0_LEN */
+ writel(0x0, mmio + RCV_RING_LEN0);
+
+ /* Clear XMT_RING0/1/2/3_LEN */
+ writel(0x0, mmio + XMT_RING_LEN0);
+ writel(0x0, mmio + XMT_RING_LEN1);
+ writel(0x0, mmio + XMT_RING_LEN2);
+ writel(0x0, mmio + XMT_RING_LEN3);
+
+ /* Clear XMT_RING_LIMIT */
+ writel(0x0, mmio + XMT_RING_LIMIT);
+
+ /* Clear MIB */
+ writew(MIB_CLEAR, mmio + MIB_ADDR);
+
+ /* Clear LARF */
+ amd8111e_writeq(*(u64*)logic_filter, mmio + LADRF);
+
+ /* SRAM_SIZE register */
+ reg_val = readl(mmio + SRAM_SIZE);
+
+ /* Set default value to CTRL1 Register */
+ writel(CTRL1_DEFAULT, mmio + CTRL1);
+
+ /* To avoid PCI posting bug */
+ readl(mmio + CMD2);
+}
+
+/*
+ * This function initializes the device registers and starts the device.
+ */
+static int amd8111e_start(struct amd8111e_priv *lp)
+{
+ struct nic *nic = lp->nic;
+ void *mmio = lp->mmio;
+ int i, reg_val;
+
+ /* stop the chip */
+ writel(RUN, mmio + CMD0);
+
+ /* AUTOPOLL0 Register *//*TBD default value is 8100 in FPS */
+ writew(0x8100 | lp->ext_phy_addr, mmio + AUTOPOLL0);
+
+ /* enable the port manager and set auto negotiation always */
+ writel(VAL1 | EN_PMGR, mmio + CMD3 );
+ writel(XPHYANE | XPHYRST, mmio + CTRL2);
+
+ /* set control registers */
+ reg_val = readl(mmio + CTRL1);
+ reg_val &= ~XMTSP_MASK;
+ writel(reg_val | XMTSP_128 | CACHE_ALIGN, mmio + CTRL1);
+
+ /* initialize tx and rx ring base addresses */
+ amd8111e_init_tx_ring(lp);
+ amd8111e_init_rx_ring(lp);
+ writel(virt_to_bus(lp->tx_ring), mmio + XMT_RING_BASE_ADDR0);
+ writel(virt_to_bus(lp->rx_ring), mmio + RCV_RING_BASE_ADDR0);
+ writew(NUM_TX_SLOTS, mmio + XMT_RING_LEN0);
+ writew(NUM_RX_SLOTS, mmio + RCV_RING_LEN0);
+
+ /* set default IPG to 96 */
+ writew(DEFAULT_IPG, mmio + IPG);
+ writew(DEFAULT_IPG - IFS1_DELTA, mmio + IFS1);
+
+ /* AutoPAD transmit, Retransmit on Underflow */
+ writel(VAL0 | APAD_XMT | REX_RTRY | REX_UFLO, mmio + CMD2);
+
+ /* JUMBO disabled */
+ writel(JUMBO, mmio + CMD3);
+
+ /* Setting the MAC address to the device */
+ for(i = 0; i < ETH_ALEN; i++)
+ writeb(nic->node_addr[i], mmio + PADR + i);
+
+ /* set RUN bit to start the chip, interrupt not enabled */
+ writel(VAL2 | RDMD0 | VAL0 | RUN, mmio + CMD0);
+
+ /* To avoid PCI posting bug */
+ readl(mmio + CMD0);
+ return 0;
+}
+
+/*
+This function will read the PHY registers.
+*/
+static int amd8111e_read_phy(struct amd8111e_priv *lp, int phy_addr, int reg, u32 *val)
+{
+ void *mmio = lp->mmio;
+ unsigned int reg_val;
+ unsigned int retry = PHY_RW_RETRY;
+
+ reg_val = readl(mmio + PHY_ACCESS);
+ while (reg_val & PHY_CMD_ACTIVE)
+ reg_val = readl(mmio + PHY_ACCESS);
+
+ writel(PHY_RD_CMD | ((phy_addr & 0x1f) << 21) | ((reg & 0x1f) << 16),
+ mmio + PHY_ACCESS);
+ do {
+ reg_val = readl(mmio + PHY_ACCESS);
+ udelay(30); /* It takes 30 us to read/write data */
+ } while (--retry && (reg_val & PHY_CMD_ACTIVE));
+
+ if (reg_val & PHY_RD_ERR) {
+ *val = 0;
+ return -1;
+ }
+
+ *val = reg_val & 0xffff;
+ return 0;
+}
+
+/*
+This function will write into PHY registers.
+*/
+#if 0
+static int amd8111e_write_phy(struct amd8111e_priv *lp, int phy_addr, int reg, u32 val)
+{
+ void *mmio = lp->mmio;
+ unsigned int reg_val;
+ unsigned int retry = PHY_RW_RETRY;
+
+ reg_val = readl(mmio + PHY_ACCESS);
+ while (reg_val & PHY_CMD_ACTIVE)
+ reg_val = readl(mmio + PHY_ACCESS);
+
+ writel(PHY_WR_CMD | ((phy_addr & 0x1f) << 21) | ((reg & 0x1f) << 16) | val,
+ mmio + PHY_ACCESS);
+ do {
+ reg_val = readl(mmio + PHY_ACCESS);
+ udelay(30); /* It takes 30 us to read/write the data */
+ } while (--retry && (reg_val & PHY_CMD_ACTIVE));
+
+ if(reg_val & PHY_RD_ERR)
+ return -1;
+
+ return 0;
+}
+#endif
+
+static void amd8111e_probe_ext_phy(struct amd8111e_priv *lp)
+{
+ int i;
+
+ lp->ext_phy_id = 0;
+ lp->ext_phy_addr = 1;
+
+ for (i = 0x1e; i >= 0; i--) {
+ u32 id1, id2;
+
+ if (amd8111e_read_phy(lp, i, MII_PHYSID1, &id1))
+ continue;
+ if (amd8111e_read_phy(lp, i, MII_PHYSID2, &id2))
+ continue;
+ lp->ext_phy_id = (id1 << 16) | id2;
+ lp->ext_phy_addr = i;
+ break;
+ }
+
+ if (lp->ext_phy_id)
+ printf("Found MII PHY ID 0x%08x at address 0x%02x\n",
+ lp->ext_phy_id, lp->ext_phy_addr);
+ else
+ printf("Couldn't detect MII PHY, assuming address 0x01\n");
+}
+
+static void amd8111e_disable_interrupt(struct amd8111e_priv *lp)
+{
+ void *mmio = lp->mmio;
+ unsigned int int0;
+
+ writel(INTREN, mmio + CMD0);
+ writel(INTEN0_CLEAR, mmio + INTEN0);
+ int0 = readl(mmio + INT0);
+ writel(int0, mmio + INT0);
+ readl(mmio + INT0);
+}
+
+static void amd8111e_enable_interrupt(struct amd8111e_priv *lp)
+{
+ void *mmio = lp->mmio;
+
+ writel(VAL3 | LCINTEN | VAL1 | TINTEN0 | VAL0 | RINTEN0, mmio + INTEN0);
+ writel(VAL0 | INTREN, mmio + CMD0);
+ readl(mmio + CMD0);
+}
+
+static void amd8111e_force_interrupt(struct amd8111e_priv *lp)
+{
+ void *mmio = lp->mmio;
+
+ writel(VAL0 | UINTCMD, mmio + CMD0);
+ readl(mmio + CMD0);
+}
+
+static int amd8111e_get_mac_address(struct amd8111e_priv *lp)
+{
+ struct nic *nic = lp->nic;
+ void *mmio = lp->mmio;
+ int i;
+
+ /* BIOS should have set mac address to PADR register,
+ * so we read PADR to get it.
+ */
+ for (i = 0; i < ETH_ALEN; i++)
+ nic->node_addr[i] = readb(mmio + PADR + i);
+ printf("Ethernet addr: %!\n", nic->node_addr);
+
+ return 0;
+}
+
+static int amd8111e_init_rx_ring(struct amd8111e_priv *lp)
+{
+ int i;
+
+ lp->rx_idx = 0;
+
+ /* Initilaizing receive descriptors */
+ for (i = 0; i < NUM_RX_SLOTS; i++) {
+ lp->rx_ring[i].buf_phy_addr = cpu_to_le32(virt_to_bus(lp->rx_buf[i]));
+ lp->rx_ring[i].buf_len = cpu_to_le16(RX_BUF_LEN);
+ wmb();
+ lp->rx_ring[i].rx_flags = cpu_to_le16(OWN_BIT);
+ }
+
+ return 0;
+}
+
+static int amd8111e_init_tx_ring(struct amd8111e_priv *lp)
+{
+ int i;
+
+ lp->tx_idx = 0;
+ lp->tx_consistent = 1;
+
+ /* Initializing transmit descriptors */
+ for (i = 0; i < NUM_TX_SLOTS; i++) {
+ lp->tx_ring[i].tx_flags = 0;
+ lp->tx_ring[i].buf_phy_addr = 0;
+ lp->tx_ring[i].buf_len = 0;
+ }
+
+ return 0;
+}
+
+static int amd8111e_wait_tx_ring(struct amd8111e_priv *lp, unsigned int index)
+{
+ volatile u16 status;
+ int retry = TX_RETRY;
+
+ status = le16_to_cpu(lp->tx_ring[index].tx_flags);
+ while (--retry && (status & OWN_BIT)) {
+ mdelay(TX_PROCESS_TIME);
+ status = le16_to_cpu(lp->tx_ring[index].tx_flags);
+ }
+ if (status & OWN_BIT) {
+ printf("Error: tx slot %d timeout, stat = 0x%x\n", index, status);
+ amd8111e_restart(lp);
+ return -1;
+ }
+
+ return 0;
+}
+
+static void amd8111e_wait_link(struct amd8111e_priv *lp)
+{
+ unsigned int status;
+ u32 reg_val;
+
+ do {
+ /* read phy to update STAT0 register */
+ amd8111e_read_phy(lp, lp->ext_phy_addr, MII_BMCR, &reg_val);
+ amd8111e_read_phy(lp, lp->ext_phy_addr, MII_BMSR, &reg_val);
+ amd8111e_read_phy(lp, lp->ext_phy_addr, MII_ADVERTISE, &reg_val);
+ amd8111e_read_phy(lp, lp->ext_phy_addr, MII_LPA, &reg_val);
+ status = readl(lp->mmio + STAT0);
+ } while (!(status & AUTONEG_COMPLETE) || !(status & LINK_STATS));
+}
+
+static void amd8111e_poll_link(struct amd8111e_priv *lp)
+{
+ unsigned int status, speed;
+ u32 reg_val;
+
+ if (!lp->link) {
+ /* read phy to update STAT0 register */
+ amd8111e_read_phy(lp, lp->ext_phy_addr, MII_BMCR, &reg_val);
+ amd8111e_read_phy(lp, lp->ext_phy_addr, MII_BMSR, &reg_val);
+ amd8111e_read_phy(lp, lp->ext_phy_addr, MII_ADVERTISE, &reg_val);
+ amd8111e_read_phy(lp, lp->ext_phy_addr, MII_LPA, &reg_val);
+ status = readl(lp->mmio + STAT0);
+
+ if (status & LINK_STATS) {
+ lp->link = 1;
+ speed = (status & SPEED_MASK) >> 7;
+ if (speed == PHY_SPEED_100)
+ lp->speed = 1;
+ else
+ lp->speed = 0;
+ if (status & FULL_DPLX)
+ lp->duplex = 1;
+ else
+ lp->duplex = 0;
+
+ printf("Link is up: %s Mbps %s duplex\n",
+ lp->speed ? "100" : "10", lp->duplex ? "full" : "half");
+ }
+ } else {
+ status = readl(lp->mmio + STAT0);
+ if (!(status & LINK_STATS)) {
+ lp->link = 0;
+ printf("Link is down\n");
+ }
+ }
+}
+
+static void amd8111e_restart(struct amd8111e_priv *lp)
+{
+ printf("\nStarting nic...\n");
+ amd8111e_disable_interrupt(lp);
+ amd8111e_init_hw_default(lp);
+ amd8111e_probe_ext_phy(lp);
+ amd8111e_get_mac_address(lp);
+ amd8111e_start(lp);
+
+ printf("Waiting link up...\n");
+ lp->link = 0;
+ amd8111e_wait_link(lp);
+ amd8111e_poll_link(lp);
+}
+
+
+/********************************************************
+ * Interface Functions *
+ ********************************************************/
+
+static void amd8111e_transmit(struct nic *nic, const char *dst_addr,
+ unsigned int type, unsigned int size, const char *packet)
+{
+ struct amd8111e_priv *lp = nic->priv_data;
+ struct eth_frame *frame;
+ unsigned int index;
+
+ /* check packet size */
+ if (size > TX_PKT_LEN_MAX) {
+ printf("amd8111e_transmit(): too large packet, drop\n");
+ return;
+ }
+
+ /* get tx slot */
+ index = lp->tx_idx;
+ if (amd8111e_wait_tx_ring(lp, index))
+ return;
+
+ /* fill frame */
+ frame = (struct eth_frame *)lp->tx_buf[index];
+ memset(frame->data, 0, TX_PKT_LEN_MAX);
+ memcpy(frame->dst_addr, dst_addr, ETH_ALEN);
+ memcpy(frame->src_addr, nic->node_addr, ETH_ALEN);
+ frame->type = htons(type);
+ memcpy(frame->data, packet, size);
+
+ /* start xmit */
+ lp->tx_ring[index].buf_len = cpu_to_le16(ETH_HLEN + size);
+ lp->tx_ring[index].buf_phy_addr = cpu_to_le32(virt_to_bus(frame));
+ wmb();
+ lp->tx_ring[index].tx_flags =
+ cpu_to_le16(OWN_BIT | STP_BIT | ENP_BIT | ADD_FCS_BIT | LTINT_BIT);
+ writel(VAL1 | TDMD0, lp->mmio + CMD0);
+ readl(lp->mmio + CMD0);
+
+ /* update slot pointer */
+ lp->tx_idx = (lp->tx_idx + 1) & TX_SLOTS_MASK;
+}
+
+static int amd8111e_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 */
+
+ struct amd8111e_priv *lp = nic->priv_data;
+ u16 status, pkt_len;
+ unsigned int index, pkt_ok;
+
+ amd8111e_poll_link(lp);
+
+ index = lp->rx_idx;
+ status = le16_to_cpu(lp->rx_ring[index].rx_flags);
+ pkt_len = le16_to_cpu(lp->rx_ring[index].msg_len) - 4; /* remove 4bytes FCS */
+
+ if (status & OWN_BIT)
+ return 0;
+
+ if (status & ERR_BIT)
+ pkt_ok = 0;
+ else if (!(status & STP_BIT))
+ pkt_ok = 0;
+ else if (!(status & ENP_BIT))
+ pkt_ok = 0;
+ else if (pkt_len < RX_PKT_LEN_MIN)
+ pkt_ok = 0;
+ else if (pkt_len > RX_PKT_LEN_MAX)
+ pkt_ok = 0;
+ else
+ pkt_ok = 1;
+
+ if (pkt_ok) {
+ if (!retrieve)
+ return 1;
+ nic->packetlen = pkt_len;
+ memcpy(nic->packet, lp->rx_buf[index], nic->packetlen);
+ }
+
+ lp->rx_ring[index].buf_phy_addr = cpu_to_le32(virt_to_bus(lp->rx_buf[index]));
+ lp->rx_ring[index].buf_len = cpu_to_le16(RX_BUF_LEN);
+ wmb();
+ lp->rx_ring[index].rx_flags = cpu_to_le16(OWN_BIT);
+ writel(VAL2 | RDMD0, lp->mmio + CMD0);
+ readl(lp->mmio + CMD0);
+
+ lp->rx_idx = (lp->rx_idx + 1) & RX_SLOTS_MASK;
+ return pkt_ok;
+}
+
+static void amd8111e_disable(struct nic *nic)
+{
+ struct amd8111e_priv *lp = nic->priv_data;
+
+ /* disable interrupt */
+ amd8111e_disable_interrupt(lp);
+
+ /* stop chip */
+ amd8111e_init_hw_default(lp);
+
+ /* unmap mmio */
+ iounmap(lp->mmio);
+
+ /* update status */
+ lp->opened = 0;
+}
+
+static void amd8111e_irq(struct nic *nic, irq_action_t action)
+{
+ struct amd8111e_priv *lp = nic->priv_data;
+
+ switch (action) {
+ case DISABLE:
+ amd8111e_disable_interrupt(lp);
+ break;
+ case ENABLE:
+ amd8111e_enable_interrupt(lp);
+ break;
+ case FORCE:
+ amd8111e_force_interrupt(lp);
+ break;
+ }
+}
+
+static struct nic_operations amd8111e_operations = {
+ .connect = dummy_connect,
+ .poll = amd8111e_poll,
+ .transmit = amd8111e_transmit,
+ .irq = amd8111e_irq,
+};
+
+static int amd8111e_probe(struct nic *nic, struct pci_device *pdev)
+{
+ struct amd8111e_priv *lp = &amd8111e;
+ unsigned long mmio_start, mmio_len;
+
+ pci_fill_nic ( nic, pdev );
+
+ mmio_start = pci_bar_start(pdev, PCI_BASE_ADDRESS_0);
+ mmio_len = pci_bar_size(pdev, PCI_BASE_ADDRESS_0);
+
+ memset(lp, 0, sizeof(*lp));
+ lp->pdev = pdev;
+ lp->nic = nic;
+ lp->mmio = ioremap(mmio_start, mmio_len);
+ lp->opened = 1;
+ adjust_pci_device(pdev);
+
+ nic->priv_data = lp;
+
+ amd8111e_restart(lp);
+
+ nic->nic_op = &amd8111e_operations;
+ return 1;
+}
+
+static struct pci_id amd8111e_nics[] = {
+ PCI_ROM(0x1022, 0x7462, "amd8111e", "AMD8111E"),
+};
+
+PCI_DRIVER ( amd8111e_driver, amd8111e_nics, PCI_NO_CLASS );
+
+DRIVER ( "AMD8111E", nic_driver, pci_driver, amd8111e_driver,
+ amd8111e_probe, amd8111e_disable );
diff --git a/src/drivers/net/amd8111e.h b/src/drivers/net/amd8111e.h
new file mode 100644
index 000000000..82b8f7a3c
--- /dev/null
+++ b/src/drivers/net/amd8111e.h
@@ -0,0 +1,629 @@
+/*
+ * Advanced Micro Devices Inc. AMD8111E Linux Network Driver
+ * Copyright (C) 2003 Advanced Micro Devices
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+
+Module Name:
+
+ amd8111e.h
+
+Abstract:
+
+ AMD8111 based 10/100 Ethernet Controller driver definitions.
+
+Environment:
+
+ Kernel Mode
+
+Revision History:
+ 3.0.0
+ Initial Revision.
+ 3.0.1
+*/
+
+#ifndef _AMD811E_H
+#define _AMD811E_H
+
+/* Command style register access
+
+Registers CMD0, CMD2, CMD3,CMD7 and INTEN0 uses a write access technique called command style access. It allows the write to selected bits of this register without altering the bits that are not selected. Command style registers are divided into 4 bytes that can be written independently. Higher order bit of each byte is the value bit that specifies the value that will be written into the selected bits of register.
+
+eg., if the value 10011010b is written into the least significant byte of a command style register, bits 1,3 and 4 of the register will be set to 1, and the other bits will not be altered. If the value 00011010b is written into the same byte, bits 1,3 and 4 will be cleared to 0 and the other bits will not be altered.
+
+*/
+
+/* Offset for Memory Mapped Registers. */
+/* 32 bit registers */
+
+#define ASF_STAT 0x00 /* ASF status register */
+#define CHIPID 0x04 /* Chip ID regsiter */
+#define MIB_DATA 0x10 /* MIB data register */
+#define MIB_ADDR 0x14 /* MIB address register */
+#define STAT0 0x30 /* Status0 register */
+#define INT0 0x38 /* Interrupt0 register */
+#define INTEN0 0x40 /* Interrupt0 enable register*/
+#define CMD0 0x48 /* Command0 register */
+#define CMD2 0x50 /* Command2 register */
+#define CMD3 0x54 /* Command3 resiter */
+#define CMD7 0x64 /* Command7 register */
+
+#define CTRL1 0x6C /* Control1 register */
+#define CTRL2 0x70 /* Control2 register */
+
+#define XMT_RING_LIMIT 0x7C /* Transmit ring limit register */
+
+#define AUTOPOLL0 0x88 /* Auto-poll0 register */
+#define AUTOPOLL1 0x8A /* Auto-poll1 register */
+#define AUTOPOLL2 0x8C /* Auto-poll2 register */
+#define AUTOPOLL3 0x8E /* Auto-poll3 register */
+#define AUTOPOLL4 0x90 /* Auto-poll4 register */
+#define AUTOPOLL5 0x92 /* Auto-poll5 register */
+
+#define AP_VALUE 0x98 /* Auto-poll value register */
+#define DLY_INT_A 0xA8 /* Group A delayed interrupt register */
+#define DLY_INT_B 0xAC /* Group B delayed interrupt register */
+
+#define FLOW_CONTROL 0xC8 /* Flow control register */
+#define PHY_ACCESS 0xD0 /* PHY access register */
+
+#define STVAL 0xD8 /* Software timer value register */
+
+#define XMT_RING_BASE_ADDR0 0x100 /* Transmit ring0 base addr register */
+#define XMT_RING_BASE_ADDR1 0x108 /* Transmit ring1 base addr register */
+#define XMT_RING_BASE_ADDR2 0x110 /* Transmit ring2 base addr register */
+#define XMT_RING_BASE_ADDR3 0x118 /* Transmit ring2 base addr register */
+
+#define RCV_RING_BASE_ADDR0 0x120 /* Transmit ring0 base addr register */
+
+#define PMAT0 0x190 /* OnNow pattern register0 */
+#define PMAT1 0x194 /* OnNow pattern register1 */
+
+/* 16bit registers */
+
+#define XMT_RING_LEN0 0x140 /* Transmit Ring0 length register */
+#define XMT_RING_LEN1 0x144 /* Transmit Ring1 length register */
+#define XMT_RING_LEN2 0x148 /* Transmit Ring2 length register */
+#define XMT_RING_LEN3 0x14C /* Transmit Ring3 length register */
+
+#define RCV_RING_LEN0 0x150 /* Receive Ring0 length register */
+
+#define SRAM_SIZE 0x178 /* SRAM size register */
+#define SRAM_BOUNDARY 0x17A /* SRAM boundary register */
+
+/* 48bit register */
+
+#define PADR 0x160 /* Physical address register */
+
+#define IFS1 0x18C /* Inter-frame spacing Part1 register */
+#define IFS 0x18D /* Inter-frame spacing register */
+#define IPG 0x18E /* Inter-frame gap register */
+/* 64bit register */
+
+#define LADRF 0x168 /* Logical address filter register */
+
+
+/* Register Bit Definitions */
+typedef enum {
+
+ ASF_INIT_DONE = (1 << 1),
+ ASF_INIT_PRESENT = (1 << 0),
+
+}STAT_ASF_BITS;
+
+typedef enum {
+
+ MIB_CMD_ACTIVE = (1 << 15 ),
+ MIB_RD_CMD = (1 << 13 ),
+ MIB_CLEAR = (1 << 12 ),
+ MIB_ADDRESS = (1 << 0) | (1 << 1) | (1 << 2) | (1 << 3)|
+ (1 << 4) | (1 << 5),
+}MIB_ADDR_BITS;
+
+
+typedef enum {
+
+ PMAT_DET = (1 << 12),
+ MP_DET = (1 << 11),
+ LC_DET = (1 << 10),
+ SPEED_MASK = (1 << 9)|(1 << 8)|(1 << 7),
+ FULL_DPLX = (1 << 6),
+ LINK_STATS = (1 << 5),
+ AUTONEG_COMPLETE = (1 << 4),
+ MIIPD = (1 << 3),
+ RX_SUSPENDED = (1 << 2),
+ TX_SUSPENDED = (1 << 1),
+ RUNNING = (1 << 0),
+
+}STAT0_BITS;
+
+#define PHY_SPEED_10 0x2
+#define PHY_SPEED_100 0x3
+
+/* INT0 0x38, 32bit register */
+typedef enum {
+
+ INTR = (1 << 31),
+ PCSINT = (1 << 28),
+ LCINT = (1 << 27),
+ APINT5 = (1 << 26),
+ APINT4 = (1 << 25),
+ APINT3 = (1 << 24),
+ TINT_SUM = (1 << 23),
+ APINT2 = (1 << 22),
+ APINT1 = (1 << 21),
+ APINT0 = (1 << 20),
+ MIIPDTINT = (1 << 19),
+ MCCINT = (1 << 17),
+ MREINT = (1 << 16),
+ RINT_SUM = (1 << 15),
+ SPNDINT = (1 << 14),
+ MPINT = (1 << 13),
+ SINT = (1 << 12),
+ TINT3 = (1 << 11),
+ TINT2 = (1 << 10),
+ TINT1 = (1 << 9),
+ TINT0 = (1 << 8),
+ UINT = (1 << 7),
+ STINT = (1 << 4),
+ RINT0 = (1 << 0),
+
+}INT0_BITS;
+
+typedef enum {
+
+ VAL3 = (1 << 31), /* VAL bit for byte 3 */
+ VAL2 = (1 << 23), /* VAL bit for byte 2 */
+ VAL1 = (1 << 15), /* VAL bit for byte 1 */
+ VAL0 = (1 << 7), /* VAL bit for byte 0 */
+
+}VAL_BITS;
+
+typedef enum {
+
+ /* VAL3 */
+ LCINTEN = (1 << 27),
+ APINT5EN = (1 << 26),
+ APINT4EN = (1 << 25),
+ APINT3EN = (1 << 24),
+ /* VAL2 */
+ APINT2EN = (1 << 22),
+ APINT1EN = (1 << 21),
+ APINT0EN = (1 << 20),
+ MIIPDTINTEN = (1 << 19),
+ MCCIINTEN = (1 << 18),
+ MCCINTEN = (1 << 17),
+ MREINTEN = (1 << 16),
+ /* VAL1 */
+ SPNDINTEN = (1 << 14),
+ MPINTEN = (1 << 13),
+ TINTEN3 = (1 << 11),
+ SINTEN = (1 << 12),
+ TINTEN2 = (1 << 10),
+ TINTEN1 = (1 << 9),
+ TINTEN0 = (1 << 8),
+ /* VAL0 */
+ STINTEN = (1 << 4),
+ RINTEN0 = (1 << 0),
+
+ INTEN0_CLEAR = 0x1F7F7F1F, /* Command style register */
+
+}INTEN0_BITS;
+
+typedef enum {
+ /* VAL2 */
+ RDMD0 = (1 << 16),
+ /* VAL1 */
+ TDMD3 = (1 << 11),
+ TDMD2 = (1 << 10),
+ TDMD1 = (1 << 9),
+ TDMD0 = (1 << 8),
+ /* VAL0 */
+ UINTCMD = (1 << 6),
+ RX_FAST_SPND = (1 << 5),
+ TX_FAST_SPND = (1 << 4),
+ RX_SPND = (1 << 3),
+ TX_SPND = (1 << 2),
+ INTREN = (1 << 1),
+ RUN = (1 << 0),
+
+ CMD0_CLEAR = 0x000F0F7F, /* Command style register */
+
+}CMD0_BITS;
+
+typedef enum {
+
+ /* VAL3 */
+ CONDUIT_MODE = (1 << 29),
+ /* VAL2 */
+ RPA = (1 << 19),
+ DRCVPA = (1 << 18),
+ DRCVBC = (1 << 17),
+ PROM = (1 << 16),
+ /* VAL1 */
+ ASTRP_RCV = (1 << 13),
+ RCV_DROP0 = (1 << 12),
+ EMBA = (1 << 11),
+ DXMT2PD = (1 << 10),
+ LTINTEN = (1 << 9),
+ DXMTFCS = (1 << 8),
+ /* VAL0 */
+ APAD_XMT = (1 << 6),
+ DRTY = (1 << 5),
+ INLOOP = (1 << 4),
+ EXLOOP = (1 << 3),
+ REX_RTRY = (1 << 2),
+ REX_UFLO = (1 << 1),
+ REX_LCOL = (1 << 0),
+
+ CMD2_CLEAR = 0x3F7F3F7F, /* Command style register */
+
+}CMD2_BITS;
+
+typedef enum {
+
+ /* VAL3 */
+ ASF_INIT_DONE_ALIAS = (1 << 29),
+ /* VAL2 */
+ JUMBO = (1 << 21),
+ VSIZE = (1 << 20),
+ VLONLY = (1 << 19),
+ VL_TAG_DEL = (1 << 18),
+ /* VAL1 */
+ EN_PMGR = (1 << 14),
+ INTLEVEL = (1 << 13),
+ FORCE_FULL_DUPLEX = (1 << 12),
+ FORCE_LINK_STATUS = (1 << 11),
+ APEP = (1 << 10),
+ MPPLBA = (1 << 9),
+ /* VAL0 */
+ RESET_PHY_PULSE = (1 << 2),
+ RESET_PHY = (1 << 1),
+ PHY_RST_POL = (1 << 0),
+
+}CMD3_BITS;
+
+
+typedef enum {
+
+ /* VAL0 */
+ PMAT_SAVE_MATCH = (1 << 4),
+ PMAT_MODE = (1 << 3),
+ MPEN_SW = (1 << 1),
+ LCMODE_SW = (1 << 0),
+
+ CMD7_CLEAR = 0x0000001B /* Command style register */
+
+}CMD7_BITS;
+
+
+typedef enum {
+
+ RESET_PHY_WIDTH = (0xF << 16) | (0xF<< 20), /* 0x00FF0000 */
+ XMTSP_MASK = (1 << 9) | (1 << 8), /* 9:8 */
+ XMTSP_128 = (1 << 9), /* 9 */
+ XMTSP_64 = (1 << 8),
+ CACHE_ALIGN = (1 << 4),
+ BURST_LIMIT_MASK = (0xF << 0 ),
+ CTRL1_DEFAULT = 0x00010111,
+
+}CTRL1_BITS;
+
+typedef enum {
+
+ FMDC_MASK = (1 << 9)|(1 << 8), /* 9:8 */
+ XPHYRST = (1 << 7),
+ XPHYANE = (1 << 6),
+ XPHYFD = (1 << 5),
+ XPHYSP = (1 << 4) | (1 << 3), /* 4:3 */
+ APDW_MASK = (1 << 2) | (1 << 1) | (1 << 0), /* 2:0 */
+
+}CTRL2_BITS;
+
+/* XMT_RING_LIMIT 0x7C, 32bit register */
+typedef enum {
+
+ XMT_RING2_LIMIT = (0xFF << 16), /* 23:16 */
+ XMT_RING1_LIMIT = (0xFF << 8), /* 15:8 */
+ XMT_RING0_LIMIT = (0xFF << 0), /* 7:0 */
+
+}XMT_RING_LIMIT_BITS;
+
+typedef enum {
+
+ AP_REG0_EN = (1 << 15),
+ AP_REG0_ADDR_MASK = (0xF << 8) |(1 << 12),/* 12:8 */
+ AP_PHY0_ADDR_MASK = (0xF << 0) |(1 << 4),/* 4:0 */
+
+}AUTOPOLL0_BITS;
+
+/* AUTOPOLL1 0x8A, 16bit register */
+typedef enum {
+
+ AP_REG1_EN = (1 << 15),
+ AP_REG1_ADDR_MASK = (0xF << 8) |(1 << 12),/* 12:8 */
+ AP_PRE_SUP1 = (1 << 6),
+ AP_PHY1_DFLT = (1 << 5),
+ AP_PHY1_ADDR_MASK = (0xF << 0) |(1 << 4),/* 4:0 */
+
+}AUTOPOLL1_BITS;
+
+
+typedef enum {
+
+ AP_REG2_EN = (1 << 15),
+ AP_REG2_ADDR_MASK = (0xF << 8) |(1 << 12),/* 12:8 */
+ AP_PRE_SUP2 = (1 << 6),
+ AP_PHY2_DFLT = (1 << 5),
+ AP_PHY2_ADDR_MASK = (0xF << 0) |(1 << 4),/* 4:0 */
+
+}AUTOPOLL2_BITS;
+
+typedef enum {
+
+ AP_REG3_EN = (1 << 15),
+ AP_REG3_ADDR_MASK = (0xF << 8) |(1 << 12),/* 12:8 */
+ AP_PRE_SUP3 = (1 << 6),
+ AP_PHY3_DFLT = (1 << 5),
+ AP_PHY3_ADDR_MASK = (0xF << 0) |(1 << 4),/* 4:0 */
+
+}AUTOPOLL3_BITS;
+
+
+typedef enum {
+
+ AP_REG4_EN = (1 << 15),
+ AP_REG4_ADDR_MASK = (0xF << 8) |(1 << 12),/* 12:8 */
+ AP_PRE_SUP4 = (1 << 6),
+ AP_PHY4_DFLT = (1 << 5),
+ AP_PHY4_ADDR_MASK = (0xF << 0) |(1 << 4),/* 4:0 */
+
+}AUTOPOLL4_BITS;
+
+
+typedef enum {
+
+ AP_REG5_EN = (1 << 15),
+ AP_REG5_ADDR_MASK = (0xF << 8) |(1 << 12),/* 12:8 */
+ AP_PRE_SUP5 = (1 << 6),
+ AP_PHY5_DFLT = (1 << 5),
+ AP_PHY5_ADDR_MASK = (0xF << 0) |(1 << 4),/* 4:0 */
+
+}AUTOPOLL5_BITS;
+
+
+
+
+/* AP_VALUE 0x98, 32bit ragister */
+typedef enum {
+
+ AP_VAL_ACTIVE = (1 << 31),
+ AP_VAL_RD_CMD = ( 1 << 29),
+ AP_ADDR = (1 << 18)|(1 << 17)|(1 << 16), /* 18:16 */
+ AP_VAL = (0xF << 0) | (0xF << 4) |( 0xF << 8) |
+ (0xF << 12), /* 15:0 */
+
+}AP_VALUE_BITS;
+
+typedef enum {
+
+ DLY_INT_A_R3 = (1 << 31),
+ DLY_INT_A_R2 = (1 << 30),
+ DLY_INT_A_R1 = (1 << 29),
+ DLY_INT_A_R0 = (1 << 28),
+ DLY_INT_A_T3 = (1 << 27),
+ DLY_INT_A_T2 = (1 << 26),
+ DLY_INT_A_T1 = (1 << 25),
+ DLY_INT_A_T0 = ( 1 << 24),
+ EVENT_COUNT_A = (0xF << 16) | (0x1 << 20),/* 20:16 */
+ MAX_DELAY_TIME_A = (0xF << 0) | (0xF << 4) | (1 << 8)|
+ (1 << 9) | (1 << 10), /* 10:0 */
+
+}DLY_INT_A_BITS;
+
+typedef enum {
+
+ DLY_INT_B_R3 = (1 << 31),
+ DLY_INT_B_R2 = (1 << 30),
+ DLY_INT_B_R1 = (1 << 29),
+ DLY_INT_B_R0 = (1 << 28),
+ DLY_INT_B_T3 = (1 << 27),
+ DLY_INT_B_T2 = (1 << 26),
+ DLY_INT_B_T1 = (1 << 25),
+ DLY_INT_B_T0 = ( 1 << 24),
+ EVENT_COUNT_B = (0xF << 16) | (0x1 << 20),/* 20:16 */
+ MAX_DELAY_TIME_B = (0xF << 0) | (0xF << 4) | (1 << 8)|
+ (1 << 9) | (1 << 10), /* 10:0 */
+}DLY_INT_B_BITS;
+
+
+/* FLOW_CONTROL 0xC8, 32bit register */
+typedef enum {
+
+ PAUSE_LEN_CHG = (1 << 30),
+ FTPE = (1 << 22),
+ FRPE = (1 << 21),
+ NAPA = (1 << 20),
+ NPA = (1 << 19),
+ FIXP = ( 1 << 18),
+ FCCMD = ( 1 << 16),
+ PAUSE_LEN = (0xF << 0) | (0xF << 4) |( 0xF << 8) | (0xF << 12), /* 15:0 */
+
+}FLOW_CONTROL_BITS;
+
+/* PHY_ ACCESS 0xD0, 32bit register */
+typedef enum {
+
+ PHY_CMD_ACTIVE = (1 << 31),
+ PHY_WR_CMD = (1 << 30),
+ PHY_RD_CMD = (1 << 29),
+ PHY_RD_ERR = (1 << 28),
+ PHY_PRE_SUP = (1 << 27),
+ PHY_ADDR = (1 << 21) | (1 << 22) | (1 << 23)|
+ (1 << 24) |(1 << 25),/* 25:21 */
+ PHY_REG_ADDR = (1 << 16) | (1 << 17) | (1 << 18)| (1 << 19) | (1 << 20),/* 20:16 */
+ PHY_DATA = (0xF << 0)|(0xF << 4) |(0xF << 8)|
+ (0xF << 12),/* 15:0 */
+
+}PHY_ACCESS_BITS;
+
+
+/* PMAT0 0x190, 32bit register */
+typedef enum {
+ PMR_ACTIVE = (1 << 31),
+ PMR_WR_CMD = (1 << 30),
+ PMR_RD_CMD = (1 << 29),
+ PMR_BANK = (1 <<28),
+ PMR_ADDR = (0xF << 16)|(1 << 20)|(1 << 21)|
+ (1 << 22),/* 22:16 */
+ PMR_B4 = (0xF << 0) | (0xF << 4),/* 15:0 */
+}PMAT0_BITS;
+
+
+/* PMAT1 0x194, 32bit register */
+typedef enum {
+ PMR_B3 = (0xF << 24) | (0xF <<28),/* 31:24 */
+ PMR_B2 = (0xF << 16) |(0xF << 20),/* 23:16 */
+ PMR_B1 = (0xF << 8) | (0xF <<12), /* 15:8 */
+ PMR_B0 = (0xF << 0)|(0xF << 4),/* 7:0 */
+}PMAT1_BITS;
+
+/************************************************************************/
+/* */
+/* MIB counter definitions */
+/* */
+/************************************************************************/
+
+#define rcv_miss_pkts 0x00
+#define rcv_octets 0x01
+#define rcv_broadcast_pkts 0x02
+#define rcv_multicast_pkts 0x03
+#define rcv_undersize_pkts 0x04
+#define rcv_oversize_pkts 0x05
+#define rcv_fragments 0x06
+#define rcv_jabbers 0x07
+#define rcv_unicast_pkts 0x08
+#define rcv_alignment_errors 0x09
+#define rcv_fcs_errors 0x0A
+#define rcv_good_octets 0x0B
+#define rcv_mac_ctrl 0x0C
+#define rcv_flow_ctrl 0x0D
+#define rcv_pkts_64_octets 0x0E
+#define rcv_pkts_65to127_octets 0x0F
+#define rcv_pkts_128to255_octets 0x10
+#define rcv_pkts_256to511_octets 0x11
+#define rcv_pkts_512to1023_octets 0x12
+#define rcv_pkts_1024to1518_octets 0x13
+#define rcv_unsupported_opcode 0x14
+#define rcv_symbol_errors 0x15
+#define rcv_drop_pkts_ring1 0x16
+#define rcv_drop_pkts_ring2 0x17
+#define rcv_drop_pkts_ring3 0x18
+#define rcv_drop_pkts_ring4 0x19
+#define rcv_jumbo_pkts 0x1A
+
+#define xmt_underrun_pkts 0x20
+#define xmt_octets 0x21
+#define xmt_packets 0x22
+#define xmt_broadcast_pkts 0x23
+#define xmt_multicast_pkts 0x24
+#define xmt_collisions 0x25
+#define xmt_unicast_pkts 0x26
+#define xmt_one_collision 0x27
+#define xmt_multiple_collision 0x28
+#define xmt_deferred_transmit 0x29
+#define xmt_late_collision 0x2A
+#define xmt_excessive_defer 0x2B
+#define xmt_loss_carrier 0x2C
+#define xmt_excessive_collision 0x2D
+#define xmt_back_pressure 0x2E
+#define xmt_flow_ctrl 0x2F
+#define xmt_pkts_64_octets 0x30
+#define xmt_pkts_65to127_octets 0x31
+#define xmt_pkts_128to255_octets 0x32
+#define xmt_pkts_256to511_octets 0x33
+#define xmt_pkts_512to1023_octets 0x34
+#define xmt_pkts_1024to1518_octet 0x35
+#define xmt_oversize_pkts 0x36
+#define xmt_jumbo_pkts 0x37
+
+/* ipg parameters */
+#define DEFAULT_IPG 0x60
+#define IFS1_DELTA 36
+#define IPG_CONVERGE_JIFFIES (HZ/2)
+#define IPG_STABLE_TIME 5
+#define MIN_IPG 96
+#define MAX_IPG 255
+#define IPG_STEP 16
+#define CSTATE 1
+#define SSTATE 2
+
+/* amd8111e decriptor flag definitions */
+typedef enum {
+
+ OWN_BIT = (1 << 15),
+ ADD_FCS_BIT = (1 << 13),
+ LTINT_BIT = (1 << 12),
+ STP_BIT = (1 << 9),
+ ENP_BIT = (1 << 8),
+ KILL_BIT = (1 << 6),
+ TCC_VLAN_INSERT = (1 << 1),
+ TCC_VLAN_REPLACE = (1 << 1) |( 1<< 0),
+
+}TX_FLAG_BITS;
+
+typedef enum {
+ ERR_BIT = (1 << 14),
+ FRAM_BIT = (1 << 13),
+ OFLO_BIT = (1 << 12),
+ CRC_BIT = (1 << 11),
+ PAM_BIT = (1 << 6),
+ LAFM_BIT = (1 << 5),
+ BAM_BIT = (1 << 4),
+ TT_VLAN_TAGGED = (1 << 3) |(1 << 2),/* 0x000 */
+ TT_PRTY_TAGGED = (1 << 3),/* 0x0008 */
+
+}RX_FLAG_BITS;
+
+#define RESET_RX_FLAGS 0x0000
+#define TT_MASK 0x000c
+#define TCC_MASK 0x0003
+
+/* driver ioctl parameters */
+#define AMD8111E_REG_DUMP_LEN 13*sizeof(u32)
+
+/* crc generator constants */
+#define CRC32 0xedb88320
+#define INITCRC 0xFFFFFFFF
+
+/* kernel provided writeq does not write 64 bits into the amd8111e device register instead writes only higher 32bits data into lower 32bits of the register.
+BUG? */
+#define amd8111e_writeq(_UlData,_memMap) \
+ writel(*(u32*)(&_UlData), _memMap); \
+ writel(*(u32*)((u8*)(&_UlData)+4), _memMap+4)
+
+/* maps the external speed options to internal value */
+typedef enum {
+ SPEED_AUTONEG,
+ SPEED10_HALF,
+ SPEED10_FULL,
+ SPEED100_HALF,
+ SPEED100_FULL,
+}EXT_PHY_OPTION;
+
+
+#endif /* _AMD8111E_H */
+
diff --git a/src/drivers/net/davicom.c b/src/drivers/net/davicom.c
index fdbf98342..d087e29e7 100644
--- a/src/drivers/net/davicom.c
+++ b/src/drivers/net/davicom.c
@@ -50,13 +50,6 @@
#define TX_TIME_OUT 2*TICKS_PER_SEC
-typedef unsigned char u8;
-typedef signed char s8;
-typedef unsigned short u16;
-typedef signed short s16;
-typedef unsigned int u32;
-typedef signed int s32;
-
/* Register offsets for davicom device */
enum davicom_offsets {
CSR0=0, CSR1=0x08, CSR2=0x10, CSR3=0x18, CSR4=0x20, CSR5=0x28,
diff --git a/src/drivers/net/depca.c b/src/drivers/net/depca.c
index 3707da64e..cc904c71e 100644
--- a/src/drivers/net/depca.c
+++ b/src/drivers/net/depca.c
@@ -413,13 +413,6 @@ static char *adapter_name[] = {
#define ALIGN8 ((u32)8 - 1) /* 2 longword (quadword) align */
#define ALIGN ALIGN8 /* Keep the LANCE happy... */
-typedef long s32;
-typedef unsigned long u32;
-typedef short s16;
-typedef unsigned short u16;
-typedef char s8;
-typedef unsigned char u8;
-
/*
** The DEPCA Rx and Tx ring descriptors.
*/
diff --git a/src/drivers/net/dmfe.c b/src/drivers/net/dmfe.c
index 4061ebfc9..e1ff44ec5 100644
--- a/src/drivers/net/dmfe.c
+++ b/src/drivers/net/dmfe.c
@@ -51,13 +51,6 @@
#define dprintf(x)
#endif
-typedef unsigned char u8;
-typedef signed char s8;
-typedef unsigned short u16;
-typedef signed short s16;
-typedef unsigned int u32;
-typedef signed int s32;
-
/* 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))
diff --git a/src/drivers/net/e1000.c b/src/drivers/net/e1000.c
index d5de2cc47..2eb6b333a 100644
--- a/src/drivers/net/e1000.c
+++ b/src/drivers/net/e1000.c
@@ -72,6 +72,9 @@ typedef enum {
* and the corresponding inplace checks inserted instead.
* Pieces such as LED handling that we definitely don't need are deleted.
*
+ * Please keep the function ordering so that it is easy to produce diffs
+ * against the linux driver.
+ *
* The following defines should not be needed normally,
* but may be helpful for debugging purposes. */
@@ -120,7 +123,9 @@ static int e1000_write_phy_reg_ex(struct e1000_hw *hw, uint32_t reg_addr, uint16
static void e1000_phy_hw_reset(struct e1000_hw *hw);
static int e1000_phy_reset(struct e1000_hw *hw);
static int e1000_detect_gig_phy(struct e1000_hw *hw);
-static void e1000_irq(struct nic *nic, irq_action_t action);
+static int e1000_read_eeprom(struct e1000_hw *hw, uint16_t offset, uint16_t words, uint16_t *data);
+static void e1000_init_rx_addrs(struct e1000_hw *hw);
+static void e1000_clear_vfta(struct e1000_hw *hw);
/* Printing macros... */
@@ -174,11 +179,18 @@ static void e1000_irq(struct nic *nic, irq_action_t action);
#define E1000_WRITE_FLUSH(a) {uint32_t x; x = E1000_READ_REG(a, STATUS);}
+
+/******************************************************************************
+ * Inline functions from e1000_main.c of the linux driver
+ ******************************************************************************/
+
+#if 0
static inline uint32_t
e1000_io_read(struct e1000_hw *hw __unused, uint32_t port)
{
return inl(port);
}
+#endif
static inline void
e1000_io_write(struct e1000_hw *hw __unused, uint32_t port, uint32_t value)
@@ -197,529 +209,10 @@ static inline void e1000_pci_clear_mwi(struct e1000_hw *hw)
hw->pci_cmd_word & ~PCI_COMMAND_INVALIDATE);
}
-/******************************************************************************
- * Raises the EEPROM's clock input.
- *
- * hw - Struct containing variables accessed by shared code
- * eecd - EECD's current value
- *****************************************************************************/
-static void
-e1000_raise_ee_clk(struct e1000_hw *hw,
- uint32_t *eecd)
-{
- /* Raise the clock input to the EEPROM (by setting the SK bit), and then
- * wait <delay> microseconds.
- */
- *eecd = *eecd | E1000_EECD_SK;
- E1000_WRITE_REG(hw, EECD, *eecd);
- E1000_WRITE_FLUSH(hw);
- udelay(hw->eeprom.delay_usec);
-}
-
-/******************************************************************************
- * Lowers the EEPROM's clock input.
- *
- * hw - Struct containing variables accessed by shared code
- * eecd - EECD's current value
- *****************************************************************************/
-static void
-e1000_lower_ee_clk(struct e1000_hw *hw,
- uint32_t *eecd)
-{
- /* Lower the clock input to the EEPROM (by clearing the SK bit), and then
- * wait 50 microseconds.
- */
- *eecd = *eecd & ~E1000_EECD_SK;
- E1000_WRITE_REG(hw, EECD, *eecd);
- E1000_WRITE_FLUSH(hw);
- udelay(hw->eeprom.delay_usec);
-}
-
-/******************************************************************************
- * Shift data bits out to the EEPROM.
- *
- * hw - Struct containing variables accessed by shared code
- * data - data to send to the EEPROM
- * count - number of bits to shift out
- *****************************************************************************/
-static void
-e1000_shift_out_ee_bits(struct e1000_hw *hw,
- uint16_t data,
- uint16_t count)
-{
- struct e1000_eeprom_info *eeprom = &hw->eeprom;
- uint32_t eecd;
- uint32_t mask;
-
- /* We need to shift "count" bits out to the EEPROM. So, value in the
- * "data" parameter will be shifted out to the EEPROM one bit at a time.
- * In order to do this, "data" must be broken down into bits.
- */
- mask = 0x01 << (count - 1);
- eecd = E1000_READ_REG(hw, EECD);
- if (eeprom->type == e1000_eeprom_microwire) {
- eecd &= ~E1000_EECD_DO;
- } else if (eeprom->type == e1000_eeprom_spi) {
- eecd |= E1000_EECD_DO;
- }
- do {
- /* A "1" is shifted out to the EEPROM by setting bit "DI" to a "1",
- * and then raising and then lowering the clock (the SK bit controls
- * the clock input to the EEPROM). A "0" is shifted out to the EEPROM
- * by setting "DI" to "0" and then raising and then lowering the clock.
- */
- eecd &= ~E1000_EECD_DI;
-
- if(data & mask)
- eecd |= E1000_EECD_DI;
-
- E1000_WRITE_REG(hw, EECD, eecd);
- E1000_WRITE_FLUSH(hw);
-
- udelay(eeprom->delay_usec);
-
- e1000_raise_ee_clk(hw, &eecd);
- e1000_lower_ee_clk(hw, &eecd);
-
- mask = mask >> 1;
-
- } while(mask);
-
- /* We leave the "DI" bit set to "0" when we leave this routine. */
- eecd &= ~E1000_EECD_DI;
- E1000_WRITE_REG(hw, EECD, eecd);
-}
-
-/******************************************************************************
- * Shift data bits in from the EEPROM
- *
- * hw - Struct containing variables accessed by shared code
- *****************************************************************************/
-static uint16_t
-e1000_shift_in_ee_bits(struct e1000_hw *hw,
- uint16_t count)
-{
- uint32_t eecd;
- uint32_t i;
- uint16_t data;
-
- /* In order to read a register from the EEPROM, we need to shift 'count'
- * bits in from the EEPROM. Bits are "shifted in" by raising the clock
- * input to the EEPROM (setting the SK bit), and then reading the value of
- * the "DO" bit. During this "shifting in" process the "DI" bit should
- * always be clear.
- */
-
- eecd = E1000_READ_REG(hw, EECD);
-
- eecd &= ~(E1000_EECD_DO | E1000_EECD_DI);
- data = 0;
-
- for(i = 0; i < count; i++) {
- data = data << 1;
- e1000_raise_ee_clk(hw, &eecd);
-
- eecd = E1000_READ_REG(hw, EECD);
-
- eecd &= ~(E1000_EECD_DI);
- if(eecd & E1000_EECD_DO)
- data |= 1;
-
- e1000_lower_ee_clk(hw, &eecd);
- }
-
- return data;
-}
-
-/******************************************************************************
- * Prepares EEPROM for access
- *
- * hw - Struct containing variables accessed by shared code
- *
- * Lowers EEPROM clock. Clears input pin. Sets the chip select pin. This
- * function should be called before issuing a command to the EEPROM.
- *****************************************************************************/
-static int32_t
-e1000_acquire_eeprom(struct e1000_hw *hw)
-{
- struct e1000_eeprom_info *eeprom = &hw->eeprom;
- uint32_t eecd, i=0;
-
- eecd = E1000_READ_REG(hw, EECD);
-
- /* Request EEPROM Access */
- if(hw->mac_type > e1000_82544) {
- eecd |= E1000_EECD_REQ;
- E1000_WRITE_REG(hw, EECD, eecd);
- eecd = E1000_READ_REG(hw, EECD);
- while((!(eecd & E1000_EECD_GNT)) &&
- (i < E1000_EEPROM_GRANT_ATTEMPTS)) {
- i++;
- udelay(5);
- eecd = E1000_READ_REG(hw, EECD);
- }
- if(!(eecd & E1000_EECD_GNT)) {
- eecd &= ~E1000_EECD_REQ;
- E1000_WRITE_REG(hw, EECD, eecd);
- DEBUGOUT("Could not acquire EEPROM grant\n");
- return -E1000_ERR_EEPROM;
- }
- }
-
- /* Setup EEPROM for Read/Write */
-
- if (eeprom->type == e1000_eeprom_microwire) {
- /* Clear SK and DI */
- eecd &= ~(E1000_EECD_DI | E1000_EECD_SK);
- E1000_WRITE_REG(hw, EECD, eecd);
-
- /* Set CS */
- eecd |= E1000_EECD_CS;
- E1000_WRITE_REG(hw, EECD, eecd);
- } else if (eeprom->type == e1000_eeprom_spi) {
- /* Clear SK and CS */
- eecd &= ~(E1000_EECD_CS | E1000_EECD_SK);
- E1000_WRITE_REG(hw, EECD, eecd);
- udelay(1);
- }
-
- return E1000_SUCCESS;
-}
-
-/******************************************************************************
- * Returns EEPROM to a "standby" state
- *
- * hw - Struct containing variables accessed by shared code
- *****************************************************************************/
-static void
-e1000_standby_eeprom(struct e1000_hw *hw)
-{
- struct e1000_eeprom_info *eeprom = &hw->eeprom;
- uint32_t eecd;
-
- eecd = E1000_READ_REG(hw, EECD);
-
- if(eeprom->type == e1000_eeprom_microwire) {
-
- /* Deselect EEPROM */
- eecd &= ~(E1000_EECD_CS | E1000_EECD_SK);
- E1000_WRITE_REG(hw, EECD, eecd);
- E1000_WRITE_FLUSH(hw);
- udelay(eeprom->delay_usec);
-
- /* Clock high */
- eecd |= E1000_EECD_SK;
- E1000_WRITE_REG(hw, EECD, eecd);
- E1000_WRITE_FLUSH(hw);
- udelay(eeprom->delay_usec);
-
- /* Select EEPROM */
- eecd |= E1000_EECD_CS;
- E1000_WRITE_REG(hw, EECD, eecd);
- E1000_WRITE_FLUSH(hw);
- udelay(eeprom->delay_usec);
-
- /* Clock low */
- eecd &= ~E1000_EECD_SK;
- E1000_WRITE_REG(hw, EECD, eecd);
- E1000_WRITE_FLUSH(hw);
- udelay(eeprom->delay_usec);
- } else if(eeprom->type == e1000_eeprom_spi) {
- /* Toggle CS to flush commands */
- eecd |= E1000_EECD_CS;
- E1000_WRITE_REG(hw, EECD, eecd);
- E1000_WRITE_FLUSH(hw);
- udelay(eeprom->delay_usec);
- eecd &= ~E1000_EECD_CS;
- E1000_WRITE_REG(hw, EECD, eecd);
- E1000_WRITE_FLUSH(hw);
- udelay(eeprom->delay_usec);
- }
-}
-
-/******************************************************************************
- * Terminates a command by inverting the EEPROM's chip select pin
- *
- * hw - Struct containing variables accessed by shared code
- *****************************************************************************/
-static void
-e1000_release_eeprom(struct e1000_hw *hw)
-{
- uint32_t eecd;
-
- eecd = E1000_READ_REG(hw, EECD);
-
- if (hw->eeprom.type == e1000_eeprom_spi) {
- eecd |= E1000_EECD_CS; /* Pull CS high */
- eecd &= ~E1000_EECD_SK; /* Lower SCK */
-
- E1000_WRITE_REG(hw, EECD, eecd);
-
- udelay(hw->eeprom.delay_usec);
- } else if(hw->eeprom.type == e1000_eeprom_microwire) {
- /* cleanup eeprom */
-
- /* CS on Microwire is active-high */
- eecd &= ~(E1000_EECD_CS | E1000_EECD_DI);
-
- E1000_WRITE_REG(hw, EECD, eecd);
-
- /* Rising edge of clock */
- eecd |= E1000_EECD_SK;
- E1000_WRITE_REG(hw, EECD, eecd);
- E1000_WRITE_FLUSH(hw);
- udelay(hw->eeprom.delay_usec);
-
- /* Falling edge of clock */
- eecd &= ~E1000_EECD_SK;
- E1000_WRITE_REG(hw, EECD, eecd);
- E1000_WRITE_FLUSH(hw);
- udelay(hw->eeprom.delay_usec);
- }
-
- /* Stop requesting EEPROM access */
- if(hw->mac_type > e1000_82544) {
- eecd &= ~E1000_EECD_REQ;
- E1000_WRITE_REG(hw, EECD, eecd);
- }
-}
-
-/******************************************************************************
- * Reads a 16 bit word from the EEPROM.
- *
- * hw - Struct containing variables accessed by shared code
- *****************************************************************************/
-static int32_t
-e1000_spi_eeprom_ready(struct e1000_hw *hw)
-{
- uint16_t retry_count = 0;
- uint8_t spi_stat_reg;
-
- /* Read "Status Register" repeatedly until the LSB is cleared. The
- * EEPROM will signal that the command has been completed by clearing
- * bit 0 of the internal status register. If it's not cleared within
- * 5 milliseconds, then error out.
- */
- retry_count = 0;
- do {
- e1000_shift_out_ee_bits(hw, EEPROM_RDSR_OPCODE_SPI,
- hw->eeprom.opcode_bits);
- spi_stat_reg = (uint8_t)e1000_shift_in_ee_bits(hw, 8);
- if (!(spi_stat_reg & EEPROM_STATUS_RDY_SPI))
- break;
-
- udelay(5);
- retry_count += 5;
-
- } while(retry_count < EEPROM_MAX_RETRY_SPI);
-
- /* ATMEL SPI write time could vary from 0-20mSec on 3.3V devices (and
- * only 0-5mSec on 5V devices)
- */
- if(retry_count >= EEPROM_MAX_RETRY_SPI) {
- DEBUGOUT("SPI EEPROM Status error\n");
- return -E1000_ERR_EEPROM;
- }
-
- return E1000_SUCCESS;
-}
/******************************************************************************
- * Reads a 16 bit word from the EEPROM.
- *
- * hw - Struct containing variables accessed by shared code
- * offset - offset of word in the EEPROM to read
- * data - word read from the EEPROM
- * words - number of words to read
- *****************************************************************************/
-static int
-e1000_read_eeprom(struct e1000_hw *hw,
- uint16_t offset,
- uint16_t words,
- uint16_t *data)
-{
- struct e1000_eeprom_info *eeprom = &hw->eeprom;
- uint32_t i = 0;
-
- DEBUGFUNC("e1000_read_eeprom");
-
- /* A check for invalid values: offset too large, too many words, and not
- * enough words.
- */
- if((offset > eeprom->word_size) || (words > eeprom->word_size - offset) ||
- (words == 0)) {
- DEBUGOUT("\"words\" parameter out of bounds\n");
- return -E1000_ERR_EEPROM;
- }
-
- /* Prepare the EEPROM for reading */
- if(e1000_acquire_eeprom(hw) != E1000_SUCCESS)
- return -E1000_ERR_EEPROM;
-
- if(eeprom->type == e1000_eeprom_spi) {
- uint16_t word_in;
- uint8_t read_opcode = EEPROM_READ_OPCODE_SPI;
-
- if(e1000_spi_eeprom_ready(hw)) {
- e1000_release_eeprom(hw);
- return -E1000_ERR_EEPROM;
- }
-
- e1000_standby_eeprom(hw);
-
- /* Some SPI eeproms use the 8th address bit embedded in the opcode */
- if((eeprom->address_bits == 8) && (offset >= 128))
- read_opcode |= EEPROM_A8_OPCODE_SPI;
-
- /* Send the READ command (opcode + addr) */
- e1000_shift_out_ee_bits(hw, read_opcode, eeprom->opcode_bits);
- e1000_shift_out_ee_bits(hw, (uint16_t)(offset*2), eeprom->address_bits);
-
- /* Read the data. The address of the eeprom internally increments with
- * each byte (spi) being read, saving on the overhead of eeprom setup
- * and tear-down. The address counter will roll over if reading beyond
- * the size of the eeprom, thus allowing the entire memory to be read
- * starting from any offset. */
- for (i = 0; i < words; i++) {
- word_in = e1000_shift_in_ee_bits(hw, 16);
- data[i] = (word_in >> 8) | (word_in << 8);
- }
- } else if(eeprom->type == e1000_eeprom_microwire) {
- for (i = 0; i < words; i++) {
- /* Send the READ command (opcode + addr) */
- e1000_shift_out_ee_bits(hw, EEPROM_READ_OPCODE_MICROWIRE,
- eeprom->opcode_bits);
- e1000_shift_out_ee_bits(hw, (uint16_t)(offset + i),
- eeprom->address_bits);
-
- /* Read the data. For microwire, each word requires the overhead
- * of eeprom setup and tear-down. */
- data[i] = e1000_shift_in_ee_bits(hw, 16);
- e1000_standby_eeprom(hw);
- }
- }
-
- /* End this read operation */
- e1000_release_eeprom(hw);
-
- return E1000_SUCCESS;
-}
-
-/******************************************************************************
- * Verifies that the EEPROM has a valid checksum
- *
- * hw - Struct containing variables accessed by shared code
- *
- * Reads the first 64 16 bit words of the EEPROM and sums the values read.
- * If the the sum of the 64 16 bit words is 0xBABA, the EEPROM's checksum is
- * valid.
- *****************************************************************************/
-static int
-e1000_validate_eeprom_checksum(struct e1000_hw *hw)
-{
- uint16_t checksum = 0;
- uint16_t i, eeprom_data;
-
- DEBUGFUNC("e1000_validate_eeprom_checksum");
-
- for(i = 0; i < (EEPROM_CHECKSUM_REG + 1); i++) {
- if(e1000_read_eeprom(hw, i, 1, &eeprom_data) < 0) {
- DEBUGOUT("EEPROM Read Error\n");
- return -E1000_ERR_EEPROM;
- }
- checksum += eeprom_data;
- }
-
- if(checksum == (uint16_t) EEPROM_SUM)
- return E1000_SUCCESS;
- else {
- DEBUGOUT("EEPROM Checksum Invalid\n");
- return -E1000_ERR_EEPROM;
- }
-}
-
-/******************************************************************************
- * Reads the adapter's MAC address from the EEPROM and inverts the LSB for the
- * second function of dual function devices
- *
- * hw - Struct containing variables accessed by shared code
- *****************************************************************************/
-static int
-e1000_read_mac_addr(struct e1000_hw *hw)
-{
- uint16_t offset;
- uint16_t eeprom_data;
- int i;
-
- DEBUGFUNC("e1000_read_mac_addr");
-
- for(i = 0; i < NODE_ADDRESS_SIZE; i += 2) {
- offset = i >> 1;
- if(e1000_read_eeprom(hw, offset, 1, &eeprom_data) < 0) {
- DEBUGOUT("EEPROM Read Error\n");
- return -E1000_ERR_EEPROM;
- }
- hw->mac_addr[i] = eeprom_data & 0xff;
- hw->mac_addr[i+1] = (eeprom_data >> 8) & 0xff;
- }
- if(((hw->mac_type == e1000_82546) || (hw->mac_type == e1000_82546_rev_3)) &&
- (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1))
- /* Invert the last bit if this is the second device */
- hw->mac_addr[5] ^= 1;
- return E1000_SUCCESS;
-}
-
-/******************************************************************************
- * Initializes receive address filters.
- *
- * hw - Struct containing variables accessed by shared code
- *
- * Places the MAC address in receive address register 0 and clears the rest
- * of the receive addresss registers. Clears the multicast table. Assumes
- * the receiver is in reset when the routine is called.
- *****************************************************************************/
-static void
-e1000_init_rx_addrs(struct e1000_hw *hw)
-{
- uint32_t i;
- uint32_t addr_low;
- uint32_t addr_high;
-
- DEBUGFUNC("e1000_init_rx_addrs");
-
- /* Setup the receive address. */
- DEBUGOUT("Programming MAC Address into RAR[0]\n");
- addr_low = (hw->mac_addr[0] |
- (hw->mac_addr[1] << 8) |
- (hw->mac_addr[2] << 16) | (hw->mac_addr[3] << 24));
-
- addr_high = (hw->mac_addr[4] |
- (hw->mac_addr[5] << 8) | E1000_RAH_AV);
-
- E1000_WRITE_REG_ARRAY(hw, RA, 0, addr_low);
- E1000_WRITE_REG_ARRAY(hw, RA, 1, addr_high);
-
- /* Zero out the other 15 receive addresses. */
- DEBUGOUT("Clearing RAR[1-15]\n");
- for(i = 1; i < E1000_RAR_ENTRIES; i++) {
- E1000_WRITE_REG_ARRAY(hw, RA, (i << 1), 0);
- E1000_WRITE_REG_ARRAY(hw, RA, ((i << 1) + 1), 0);
- }
-}
-
-/******************************************************************************
- * Clears the VLAN filer table
- *
- * hw - Struct containing variables accessed by shared code
- *****************************************************************************/
-static void
-e1000_clear_vfta(struct e1000_hw *hw)
-{
- uint32_t offset;
-
- for(offset = 0; offset < E1000_VLAN_FILTER_TBL_SIZE; offset++)
- E1000_WRITE_REG_ARRAY(hw, VFTA, offset, 0);
-}
+ * Inline functions from e1000_hw.c of the linux driver
+ ******************************************************************************/
/******************************************************************************
* Writes a value to one of the devices registers using port I/O (as opposed to
@@ -733,6 +226,11 @@ static inline void e1000_write_reg_io(struct e1000_hw *hw, uint32_t offset,
e1000_io_write(hw, hw->io_base + 4, value);
}
+
+/******************************************************************************
+ * Functions from e1000_hw.c of the linux driver
+ ******************************************************************************/
+
/******************************************************************************
* Set the phy type member in the hw struct.
*
@@ -3252,6 +2750,535 @@ e1000_init_eeprom_params(struct e1000_hw *hw)
}
}
+/******************************************************************************
+ * Raises the EEPROM's clock input.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * eecd - EECD's current value
+ *****************************************************************************/
+static void
+e1000_raise_ee_clk(struct e1000_hw *hw,
+ uint32_t *eecd)
+{
+ /* Raise the clock input to the EEPROM (by setting the SK bit), and then
+ * wait <delay> microseconds.
+ */
+ *eecd = *eecd | E1000_EECD_SK;
+ E1000_WRITE_REG(hw, EECD, *eecd);
+ E1000_WRITE_FLUSH(hw);
+ udelay(hw->eeprom.delay_usec);
+}
+
+/******************************************************************************
+ * Lowers the EEPROM's clock input.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * eecd - EECD's current value
+ *****************************************************************************/
+static void
+e1000_lower_ee_clk(struct e1000_hw *hw,
+ uint32_t *eecd)
+{
+ /* Lower the clock input to the EEPROM (by clearing the SK bit), and then
+ * wait 50 microseconds.
+ */
+ *eecd = *eecd & ~E1000_EECD_SK;
+ E1000_WRITE_REG(hw, EECD, *eecd);
+ E1000_WRITE_FLUSH(hw);
+ udelay(hw->eeprom.delay_usec);
+}
+
+/******************************************************************************
+ * Shift data bits out to the EEPROM.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * data - data to send to the EEPROM
+ * count - number of bits to shift out
+ *****************************************************************************/
+static void
+e1000_shift_out_ee_bits(struct e1000_hw *hw,
+ uint16_t data,
+ uint16_t count)
+{
+ struct e1000_eeprom_info *eeprom = &hw->eeprom;
+ uint32_t eecd;
+ uint32_t mask;
+
+ /* We need to shift "count" bits out to the EEPROM. So, value in the
+ * "data" parameter will be shifted out to the EEPROM one bit at a time.
+ * In order to do this, "data" must be broken down into bits.
+ */
+ mask = 0x01 << (count - 1);
+ eecd = E1000_READ_REG(hw, EECD);
+ if (eeprom->type == e1000_eeprom_microwire) {
+ eecd &= ~E1000_EECD_DO;
+ } else if (eeprom->type == e1000_eeprom_spi) {
+ eecd |= E1000_EECD_DO;
+ }
+ do {
+ /* A "1" is shifted out to the EEPROM by setting bit "DI" to a "1",
+ * and then raising and then lowering the clock (the SK bit controls
+ * the clock input to the EEPROM). A "0" is shifted out to the EEPROM
+ * by setting "DI" to "0" and then raising and then lowering the clock.
+ */
+ eecd &= ~E1000_EECD_DI;
+
+ if(data & mask)
+ eecd |= E1000_EECD_DI;
+
+ E1000_WRITE_REG(hw, EECD, eecd);
+ E1000_WRITE_FLUSH(hw);
+
+ udelay(eeprom->delay_usec);
+
+ e1000_raise_ee_clk(hw, &eecd);
+ e1000_lower_ee_clk(hw, &eecd);
+
+ mask = mask >> 1;
+
+ } while(mask);
+
+ /* We leave the "DI" bit set to "0" when we leave this routine. */
+ eecd &= ~E1000_EECD_DI;
+ E1000_WRITE_REG(hw, EECD, eecd);
+}
+
+/******************************************************************************
+ * Shift data bits in from the EEPROM
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+static uint16_t
+e1000_shift_in_ee_bits(struct e1000_hw *hw,
+ uint16_t count)
+{
+ uint32_t eecd;
+ uint32_t i;
+ uint16_t data;
+
+ /* In order to read a register from the EEPROM, we need to shift 'count'
+ * bits in from the EEPROM. Bits are "shifted in" by raising the clock
+ * input to the EEPROM (setting the SK bit), and then reading the value of
+ * the "DO" bit. During this "shifting in" process the "DI" bit should
+ * always be clear.
+ */
+
+ eecd = E1000_READ_REG(hw, EECD);
+
+ eecd &= ~(E1000_EECD_DO | E1000_EECD_DI);
+ data = 0;
+
+ for(i = 0; i < count; i++) {
+ data = data << 1;
+ e1000_raise_ee_clk(hw, &eecd);
+
+ eecd = E1000_READ_REG(hw, EECD);
+
+ eecd &= ~(E1000_EECD_DI);
+ if(eecd & E1000_EECD_DO)
+ data |= 1;
+
+ e1000_lower_ee_clk(hw, &eecd);
+ }
+
+ return data;
+}
+
+/******************************************************************************
+ * Prepares EEPROM for access
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Lowers EEPROM clock. Clears input pin. Sets the chip select pin. This
+ * function should be called before issuing a command to the EEPROM.
+ *****************************************************************************/
+static int32_t
+e1000_acquire_eeprom(struct e1000_hw *hw)
+{
+ struct e1000_eeprom_info *eeprom = &hw->eeprom;
+ uint32_t eecd, i=0;
+
+ eecd = E1000_READ_REG(hw, EECD);
+
+ /* Request EEPROM Access */
+ if(hw->mac_type > e1000_82544) {
+ eecd |= E1000_EECD_REQ;
+ E1000_WRITE_REG(hw, EECD, eecd);
+ eecd = E1000_READ_REG(hw, EECD);
+ while((!(eecd & E1000_EECD_GNT)) &&
+ (i < E1000_EEPROM_GRANT_ATTEMPTS)) {
+ i++;
+ udelay(5);
+ eecd = E1000_READ_REG(hw, EECD);
+ }
+ if(!(eecd & E1000_EECD_GNT)) {
+ eecd &= ~E1000_EECD_REQ;
+ E1000_WRITE_REG(hw, EECD, eecd);
+ DEBUGOUT("Could not acquire EEPROM grant\n");
+ return -E1000_ERR_EEPROM;
+ }
+ }
+
+ /* Setup EEPROM for Read/Write */
+
+ if (eeprom->type == e1000_eeprom_microwire) {
+ /* Clear SK and DI */
+ eecd &= ~(E1000_EECD_DI | E1000_EECD_SK);
+ E1000_WRITE_REG(hw, EECD, eecd);
+
+ /* Set CS */
+ eecd |= E1000_EECD_CS;
+ E1000_WRITE_REG(hw, EECD, eecd);
+ } else if (eeprom->type == e1000_eeprom_spi) {
+ /* Clear SK and CS */
+ eecd &= ~(E1000_EECD_CS | E1000_EECD_SK);
+ E1000_WRITE_REG(hw, EECD, eecd);
+ udelay(1);
+ }
+
+ return E1000_SUCCESS;
+}
+
+/******************************************************************************
+ * Returns EEPROM to a "standby" state
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+static void
+e1000_standby_eeprom(struct e1000_hw *hw)
+{
+ struct e1000_eeprom_info *eeprom = &hw->eeprom;
+ uint32_t eecd;
+
+ eecd = E1000_READ_REG(hw, EECD);
+
+ if(eeprom->type == e1000_eeprom_microwire) {
+
+ /* Deselect EEPROM */
+ eecd &= ~(E1000_EECD_CS | E1000_EECD_SK);
+ E1000_WRITE_REG(hw, EECD, eecd);
+ E1000_WRITE_FLUSH(hw);
+ udelay(eeprom->delay_usec);
+
+ /* Clock high */
+ eecd |= E1000_EECD_SK;
+ E1000_WRITE_REG(hw, EECD, eecd);
+ E1000_WRITE_FLUSH(hw);
+ udelay(eeprom->delay_usec);
+
+ /* Select EEPROM */
+ eecd |= E1000_EECD_CS;
+ E1000_WRITE_REG(hw, EECD, eecd);
+ E1000_WRITE_FLUSH(hw);
+ udelay(eeprom->delay_usec);
+
+ /* Clock low */
+ eecd &= ~E1000_EECD_SK;
+ E1000_WRITE_REG(hw, EECD, eecd);
+ E1000_WRITE_FLUSH(hw);
+ udelay(eeprom->delay_usec);
+ } else if(eeprom->type == e1000_eeprom_spi) {
+ /* Toggle CS to flush commands */
+ eecd |= E1000_EECD_CS;
+ E1000_WRITE_REG(hw, EECD, eecd);
+ E1000_WRITE_FLUSH(hw);
+ udelay(eeprom->delay_usec);
+ eecd &= ~E1000_EECD_CS;
+ E1000_WRITE_REG(hw, EECD, eecd);
+ E1000_WRITE_FLUSH(hw);
+ udelay(eeprom->delay_usec);
+ }
+}
+
+/******************************************************************************
+ * Terminates a command by inverting the EEPROM's chip select pin
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+static void
+e1000_release_eeprom(struct e1000_hw *hw)
+{
+ uint32_t eecd;
+
+ eecd = E1000_READ_REG(hw, EECD);
+
+ if (hw->eeprom.type == e1000_eeprom_spi) {
+ eecd |= E1000_EECD_CS; /* Pull CS high */
+ eecd &= ~E1000_EECD_SK; /* Lower SCK */
+
+ E1000_WRITE_REG(hw, EECD, eecd);
+
+ udelay(hw->eeprom.delay_usec);
+ } else if(hw->eeprom.type == e1000_eeprom_microwire) {
+ /* cleanup eeprom */
+
+ /* CS on Microwire is active-high */
+ eecd &= ~(E1000_EECD_CS | E1000_EECD_DI);
+
+ E1000_WRITE_REG(hw, EECD, eecd);
+
+ /* Rising edge of clock */
+ eecd |= E1000_EECD_SK;
+ E1000_WRITE_REG(hw, EECD, eecd);
+ E1000_WRITE_FLUSH(hw);
+ udelay(hw->eeprom.delay_usec);
+
+ /* Falling edge of clock */
+ eecd &= ~E1000_EECD_SK;
+ E1000_WRITE_REG(hw, EECD, eecd);
+ E1000_WRITE_FLUSH(hw);
+ udelay(hw->eeprom.delay_usec);
+ }
+
+ /* Stop requesting EEPROM access */
+ if(hw->mac_type > e1000_82544) {
+ eecd &= ~E1000_EECD_REQ;
+ E1000_WRITE_REG(hw, EECD, eecd);
+ }
+}
+
+/******************************************************************************
+ * Reads a 16 bit word from the EEPROM.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+static int32_t
+e1000_spi_eeprom_ready(struct e1000_hw *hw)
+{
+ uint16_t retry_count = 0;
+ uint8_t spi_stat_reg;
+
+ /* Read "Status Register" repeatedly until the LSB is cleared. The
+ * EEPROM will signal that the command has been completed by clearing
+ * bit 0 of the internal status register. If it's not cleared within
+ * 5 milliseconds, then error out.
+ */
+ retry_count = 0;
+ do {
+ e1000_shift_out_ee_bits(hw, EEPROM_RDSR_OPCODE_SPI,
+ hw->eeprom.opcode_bits);
+ spi_stat_reg = (uint8_t)e1000_shift_in_ee_bits(hw, 8);
+ if (!(spi_stat_reg & EEPROM_STATUS_RDY_SPI))
+ break;
+
+ udelay(5);
+ retry_count += 5;
+
+ } while(retry_count < EEPROM_MAX_RETRY_SPI);
+
+ /* ATMEL SPI write time could vary from 0-20mSec on 3.3V devices (and
+ * only 0-5mSec on 5V devices)
+ */
+ if(retry_count >= EEPROM_MAX_RETRY_SPI) {
+ DEBUGOUT("SPI EEPROM Status error\n");
+ return -E1000_ERR_EEPROM;
+ }
+
+ return E1000_SUCCESS;
+}
+
+/******************************************************************************
+ * Reads a 16 bit word from the EEPROM.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * offset - offset of word in the EEPROM to read
+ * data - word read from the EEPROM
+ * words - number of words to read
+ *****************************************************************************/
+static int
+e1000_read_eeprom(struct e1000_hw *hw,
+ uint16_t offset,
+ uint16_t words,
+ uint16_t *data)
+{
+ struct e1000_eeprom_info *eeprom = &hw->eeprom;
+ uint32_t i = 0;
+
+ DEBUGFUNC("e1000_read_eeprom");
+
+ /* A check for invalid values: offset too large, too many words, and not
+ * enough words.
+ */
+ if((offset > eeprom->word_size) || (words > eeprom->word_size - offset) ||
+ (words == 0)) {
+ DEBUGOUT("\"words\" parameter out of bounds\n");
+ return -E1000_ERR_EEPROM;
+ }
+
+ /* Prepare the EEPROM for reading */
+ if(e1000_acquire_eeprom(hw) != E1000_SUCCESS)
+ return -E1000_ERR_EEPROM;
+
+ if(eeprom->type == e1000_eeprom_spi) {
+ uint16_t word_in;
+ uint8_t read_opcode = EEPROM_READ_OPCODE_SPI;
+
+ if(e1000_spi_eeprom_ready(hw)) {
+ e1000_release_eeprom(hw);
+ return -E1000_ERR_EEPROM;
+ }
+
+ e1000_standby_eeprom(hw);
+
+ /* Some SPI eeproms use the 8th address bit embedded in the opcode */
+ if((eeprom->address_bits == 8) && (offset >= 128))
+ read_opcode |= EEPROM_A8_OPCODE_SPI;
+
+ /* Send the READ command (opcode + addr) */
+ e1000_shift_out_ee_bits(hw, read_opcode, eeprom->opcode_bits);
+ e1000_shift_out_ee_bits(hw, (uint16_t)(offset*2), eeprom->address_bits);
+
+ /* Read the data. The address of the eeprom internally increments with
+ * each byte (spi) being read, saving on the overhead of eeprom setup
+ * and tear-down. The address counter will roll over if reading beyond
+ * the size of the eeprom, thus allowing the entire memory to be read
+ * starting from any offset. */
+ for (i = 0; i < words; i++) {
+ word_in = e1000_shift_in_ee_bits(hw, 16);
+ data[i] = (word_in >> 8) | (word_in << 8);
+ }
+ } else if(eeprom->type == e1000_eeprom_microwire) {
+ for (i = 0; i < words; i++) {
+ /* Send the READ command (opcode + addr) */
+ e1000_shift_out_ee_bits(hw, EEPROM_READ_OPCODE_MICROWIRE,
+ eeprom->opcode_bits);
+ e1000_shift_out_ee_bits(hw, (uint16_t)(offset + i),
+ eeprom->address_bits);
+
+ /* Read the data. For microwire, each word requires the overhead
+ * of eeprom setup and tear-down. */
+ data[i] = e1000_shift_in_ee_bits(hw, 16);
+ e1000_standby_eeprom(hw);
+ }
+ }
+
+ /* End this read operation */
+ e1000_release_eeprom(hw);
+
+ return E1000_SUCCESS;
+}
+
+/******************************************************************************
+ * Verifies that the EEPROM has a valid checksum
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Reads the first 64 16 bit words of the EEPROM and sums the values read.
+ * If the the sum of the 64 16 bit words is 0xBABA, the EEPROM's checksum is
+ * valid.
+ *****************************************************************************/
+static int
+e1000_validate_eeprom_checksum(struct e1000_hw *hw)
+{
+ uint16_t checksum = 0;
+ uint16_t i, eeprom_data;
+
+ DEBUGFUNC("e1000_validate_eeprom_checksum");
+
+ for(i = 0; i < (EEPROM_CHECKSUM_REG + 1); i++) {
+ if(e1000_read_eeprom(hw, i, 1, &eeprom_data) < 0) {
+ DEBUGOUT("EEPROM Read Error\n");
+ return -E1000_ERR_EEPROM;
+ }
+ checksum += eeprom_data;
+ }
+
+ if(checksum == (uint16_t) EEPROM_SUM)
+ return E1000_SUCCESS;
+ else {
+ DEBUGOUT("EEPROM Checksum Invalid\n");
+ return -E1000_ERR_EEPROM;
+ }
+}
+
+/******************************************************************************
+ * Reads the adapter's MAC address from the EEPROM and inverts the LSB for the
+ * second function of dual function devices
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+static int
+e1000_read_mac_addr(struct e1000_hw *hw)
+{
+ uint16_t offset;
+ uint16_t eeprom_data;
+ int i;
+
+ DEBUGFUNC("e1000_read_mac_addr");
+
+ for(i = 0; i < NODE_ADDRESS_SIZE; i += 2) {
+ offset = i >> 1;
+ if(e1000_read_eeprom(hw, offset, 1, &eeprom_data) < 0) {
+ DEBUGOUT("EEPROM Read Error\n");
+ return -E1000_ERR_EEPROM;
+ }
+ hw->mac_addr[i] = eeprom_data & 0xff;
+ hw->mac_addr[i+1] = (eeprom_data >> 8) & 0xff;
+ }
+ if(((hw->mac_type == e1000_82546) || (hw->mac_type == e1000_82546_rev_3)) &&
+ (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1))
+ /* Invert the last bit if this is the second device */
+ hw->mac_addr[5] ^= 1;
+ return E1000_SUCCESS;
+}
+
+/******************************************************************************
+ * Initializes receive address filters.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Places the MAC address in receive address register 0 and clears the rest
+ * of the receive addresss registers. Clears the multicast table. Assumes
+ * the receiver is in reset when the routine is called.
+ *****************************************************************************/
+static void
+e1000_init_rx_addrs(struct e1000_hw *hw)
+{
+ uint32_t i;
+ uint32_t addr_low;
+ uint32_t addr_high;
+
+ DEBUGFUNC("e1000_init_rx_addrs");
+
+ /* Setup the receive address. */
+ DEBUGOUT("Programming MAC Address into RAR[0]\n");
+ addr_low = (hw->mac_addr[0] |
+ (hw->mac_addr[1] << 8) |
+ (hw->mac_addr[2] << 16) | (hw->mac_addr[3] << 24));
+
+ addr_high = (hw->mac_addr[4] |
+ (hw->mac_addr[5] << 8) | E1000_RAH_AV);
+
+ E1000_WRITE_REG_ARRAY(hw, RA, 0, addr_low);
+ E1000_WRITE_REG_ARRAY(hw, RA, 1, addr_high);
+
+ /* Zero out the other 15 receive addresses. */
+ DEBUGOUT("Clearing RAR[1-15]\n");
+ for(i = 1; i < E1000_RAR_ENTRIES; i++) {
+ E1000_WRITE_REG_ARRAY(hw, RA, (i << 1), 0);
+ E1000_WRITE_REG_ARRAY(hw, RA, ((i << 1) + 1), 0);
+ }
+}
+
+/******************************************************************************
+ * Clears the VLAN filer table
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+static void
+e1000_clear_vfta(struct e1000_hw *hw)
+{
+ uint32_t offset;
+
+ for(offset = 0; offset < E1000_VLAN_FILTER_TBL_SIZE; offset++)
+ E1000_WRITE_REG_ARRAY(hw, VFTA, offset, 0);
+}
+
+
+/******************************************************************************
+ * Functions from e1000_main.c of the linux driver
+ ******************************************************************************/
+
/**
* e1000_reset - Reset the adapter
*/
@@ -3357,6 +3384,11 @@ e1000_sw_init(struct pci_device *pdev, struct e1000_hw *hw)
return E1000_SUCCESS;
}
+
+/******************************************************************************
+ * Functions not present in the linux driver
+ ******************************************************************************/
+
static void fill_rx (void)
{
struct e1000_rx_desc *rd;
diff --git a/src/drivers/net/eepro.c b/src/drivers/net/eepro.c
index 6c2318bdd..65c6c8f59 100644
--- a/src/drivers/net/eepro.c
+++ b/src/drivers/net/eepro.c
@@ -19,6 +19,12 @@ has 34 pins, the top row of 2 are not used.
***************************************************************************/
/*
+
+ timlegge 2005-05-18 remove the relocation changes cards that
+ write directly to the hardware don't need it
+*/
+
+/*
* 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, or (at
@@ -257,8 +263,8 @@ static unsigned eeprom_reg = EEPROM_REG_PRO;
#define eeprom_delay() { udelay(40); }
#define EE_READ_CMD (6 << 6)
-/* do a full reset */
-#define eepro_full_reset(ioaddr) outb(RESET_CMD, ioaddr); udelay(40);
+/* do a full reset; data sheet asks for 250us delay */
+#define eepro_full_reset(ioaddr) outb(RESET_CMD, ioaddr); udelay(255);
/* do a nice reset */
#define eepro_sel_reset(ioaddr) { \
@@ -320,13 +326,15 @@ static void eepro_reset(struct nic *nic)
eepro_sw2bank0(nic->ioaddr); /* Switch back to bank 0 */
eepro_clear_int(nic->ioaddr);
/* Initialise RCV */
- rx_start = (unsigned int)bus_to_virt(RCV_LOWER_LIMIT << 8);
- outw(RCV_LOWER_LIMIT << 8, nic->ioaddr + RCV_BAR);
+ outw(rx_start = (RCV_LOWER_LIMIT << 8), nic->ioaddr + RCV_BAR);
outw(((RCV_UPPER_LIMIT << 8) | 0xFE), nic->ioaddr + RCV_STOP);
+ /* Make sure 1st poll won't find a valid packet header */
+ outw((RCV_LOWER_LIMIT << 8), nic->ioaddr + HOST_ADDRESS_REG);
+ outw(0, nic->ioaddr + IO_PORT);
/* Intialise XMT */
outw((XMT_LOWER_LIMIT << 8), nic->ioaddr + xmt_bar);
eepro_sel_reset(nic->ioaddr);
- tx_start = tx_end = (unsigned int)bus_to_virt(XMT_LOWER_LIMIT << 8);
+ tx_start = tx_end = (XMT_LOWER_LIMIT << 8);
tx_last = 0;
eepro_en_rx(nic->ioaddr);
}
@@ -336,7 +344,7 @@ POLL - Wait for a frame
***************************************************************************/
static int eepro_poll(struct nic *nic, int retrieve)
{
- unsigned int rcv_car = virt_to_bus((void *)rx_start);
+ unsigned int rcv_car = rx_start;
unsigned int rcv_event, rcv_status, rcv_next_frame, rcv_size;
/* return true if there's an ethernet packet ready to read */
@@ -380,8 +388,12 @@ static int eepro_poll(struct nic *nic, int retrieve)
}
#endif
nic->packetlen = rcv_size;
- rcv_car = virt_to_bus((void *) (rx_start + RCV_HEADER + rcv_size));
- rx_start = (unsigned int)bus_to_virt(rcv_next_frame << 8);
+ rcv_car = (rx_start + RCV_HEADER + rcv_size);
+ rx_start = rcv_next_frame;
+/*
+ hex_dump(rcv_car, nic->packetlen);
+*/
+
if (rcv_car == 0)
rcv_car = ((RCV_UPPER_LIMIT << 8) | 0xff);
outw(rcv_car - 1, nic->ioaddr + RCV_STOP);
@@ -455,7 +467,7 @@ static void eepro_disable ( struct nic *nic, struct isa_device *isa __unused ) {
eepro_sw2bank0(nic->ioaddr); /* Switch to bank 0 */
/* Flush the Tx and disable Rx */
outb(STOP_RCV_CMD, nic->ioaddr);
- tx_start = tx_end = (unsigned int) (bus_to_virt(XMT_LOWER_LIMIT << 8));
+ tx_start = tx_end = (XMT_LOWER_LIMIT << 8);
tx_last = 0;
/* Reset the 82595 */
eepro_full_reset(nic->ioaddr);
diff --git a/src/drivers/net/eepro100.c b/src/drivers/net/eepro100.c
index 590b37c8d..d97b1b187 100644
--- a/src/drivers/net/eepro100.c
+++ b/src/drivers/net/eepro100.c
@@ -110,13 +110,6 @@
static int ioaddr;
-typedef unsigned char u8;
-typedef signed char s8;
-typedef unsigned short u16;
-typedef signed short s16;
-typedef unsigned int u32;
-typedef signed int s32;
-
enum speedo_offsets {
SCBStatus = 0, SCBCmd = 2, /* Rx/Command Unit command and status. */
SCBPointer = 4, /* General purpose pointer. */
diff --git a/src/drivers/net/forcedeth.c b/src/drivers/net/forcedeth.c
index 3297effd1..637738362 100644
--- a/src/drivers/net/forcedeth.c
+++ b/src/drivers/net/forcedeth.c
@@ -30,14 +30,16 @@
* (C) 2003 Manfred Spraul
* See Linux Driver for full information
*
-* Linux Driver Version 0.22, 19 Jan 2004
+* Linux Driver Version 0.30, 25 Sep 2004
+* Linux Kernel 2.6.10
*
*
* REVISION HISTORY:
* ================
* v1.0 01-31-2004 timlegge Initial port of Linux driver
* v1.1 02-03-2004 timlegge Large Clean up, first release
-*
+* v1.2 05-14-2005 timlegge Add Linux 0.22 to .030 features
+*
* Indent Options: indent -kr -i8
***************************************************************************/
@@ -49,9 +51,10 @@
#include "pci.h"
/* Include timer support functions */
#include "timer.h"
+#include "mii.h"
-#define drv_version "v1.1"
-#define drv_date "02-03-2004"
+#define drv_version "v1.2"
+#define drv_date "05-14-2005"
//#define TFTM_DEBUG
#ifdef TFTM_DEBUG
@@ -60,12 +63,7 @@
#define dprintf(x)
#endif
-typedef unsigned char u8;
-typedef signed char s8;
-typedef unsigned short u16;
-typedef signed short s16;
-typedef unsigned int u32;
-typedef signed int s32;
+#define ETH_DATA_LEN 1500
/* Condensed operations for readability. */
#define virt_to_le32desc(addr) cpu_to_le32(virt_to_bus(addr))
@@ -73,22 +71,35 @@ typedef signed int s32;
static unsigned long BASE;
/* NIC specific static variables go here */
+#define PCI_DEVICE_ID_NVIDIA_NVENET_1 0x01c3
+#define PCI_DEVICE_ID_NVIDIA_NVENET_2 0x0066
+#define PCI_DEVICE_ID_NVIDIA_NVENET_4 0x0086
+#define PCI_DEVICE_ID_NVIDIA_NVENET_5 0x008c
+#define PCI_DEVICE_ID_NVIDIA_NVENET_3 0x00d6
+#define PCI_DEVICE_ID_NVIDIA_NVENET_7 0x00df
+#define PCI_DEVICE_ID_NVIDIA_NVENET_6 0x00e6
+#define PCI_DEVICE_ID_NVIDIA_NVENET_8 0x0056
+#define PCI_DEVICE_ID_NVIDIA_NVENET_9 0x0057
+#define PCI_DEVICE_ID_NVIDIA_NVENET_10 0x0037
+#define PCI_DEVICE_ID_NVIDIA_NVENET_11 0x0038
/*
* Hardware access:
*/
-#define DEV_NEED_LASTPACKET1 0x0001
-#define DEV_IRQMASK_1 0x0002
-#define DEV_IRQMASK_2 0x0004
-#define DEV_NEED_TIMERIRQ 0x0008
+#define DEV_NEED_LASTPACKET1 0x0001 /* set LASTPACKET1 in tx flags */
+#define DEV_IRQMASK_1 0x0002 /* use NVREG_IRQMASK_WANTED_1 for irq mask */
+#define DEV_IRQMASK_2 0x0004 /* use NVREG_IRQMASK_WANTED_2 for irq mask */
+#define DEV_NEED_TIMERIRQ 0x0008 /* set the timer irq flag in the irq mask */
+#define DEV_NEED_LINKTIMER 0x0010 /* poll link settings. Relies on the timer irq */
enum {
NvRegIrqStatus = 0x000,
#define NVREG_IRQSTAT_MIIEVENT 0040
#define NVREG_IRQSTAT_MASK 0x1ff
NvRegIrqMask = 0x004,
+#define NVREG_IRQ_RX_ERROR 0x0001
#define NVREG_IRQ_RX 0x0002
#define NVREG_IRQ_RX_NOBUF 0x0004
#define NVREG_IRQ_TX_ERR 0x0008
@@ -98,7 +109,7 @@ enum {
#define NVREG_IRQ_TX1 0x0100
#define NVREG_IRQMASK_WANTED_1 0x005f
#define NVREG_IRQMASK_WANTED_2 0x0147
-#define NVREG_IRQ_UNKNOWN (~(NVREG_IRQ_RX|NVREG_IRQ_RX_NOBUF|NVREG_IRQ_TX_ERR|NVREG_IRQ_TX2|NVREG_IRQ_TIMER|NVREG_IRQ_LINK|NVREG_IRQ_TX1))
+#define NVREG_IRQ_UNKNOWN (~(NVREG_IRQ_RX_ERROR|NVREG_IRQ_RX|NVREG_IRQ_RX_NOBUF|NVREG_IRQ_TX_ERR|NVREG_IRQ_TX2|NVREG_IRQ_TIMER|NVREG_IRQ_LINK|NVREG_IRQ_TX1))
NvRegUnknownSetupReg6 = 0x008,
#define NVREG_UNKSETUP6_VAL 3
@@ -125,7 +136,7 @@ enum {
NvRegOffloadConfig = 0x90,
#define NVREG_OFFLOAD_HOMEPHY 0x601
-#define NVREG_OFFLOAD_NORMAL 0x5ee
+#define NVREG_OFFLOAD_NORMAL RX_NIC_BUFSIZE
NvRegReceiverControl = 0x094,
#define NVREG_RCVCTL_START 0x01
NvRegReceiverStatus = 0x98,
@@ -134,6 +145,8 @@ enum {
NvRegRandomSeed = 0x9c,
#define NVREG_RNDSEED_MASK 0x00ff
#define NVREG_RNDSEED_FORCE 0x7f00
+#define NVREG_RNDSEED_FORCE2 0x2d00
+#define NVREG_RNDSEED_FORCE3 0x7400
NvRegUnknownSetupReg1 = 0xA0,
#define NVREG_UNKSETUP1_VAL 0x16070f
@@ -147,6 +160,9 @@ enum {
NvRegMulticastMaskA = 0xB8,
NvRegMulticastMaskB = 0xBC,
+ NvRegPhyInterface = 0xC0,
+#define PHY_RGMII 0x10000000
+
NvRegTxRingPhysAddr = 0x100,
NvRegRxRingPhysAddr = 0x104,
NvRegRingSizes = 0x108,
@@ -155,12 +171,12 @@ enum {
NvRegUnknownTransmitterReg = 0x10c,
NvRegLinkSpeed = 0x110,
#define NVREG_LINKSPEED_FORCE 0x10000
-#define NVREG_LINKSPEED_10 10
+#define NVREG_LINKSPEED_10 1000
#define NVREG_LINKSPEED_100 100
-#define NVREG_LINKSPEED_1000 1000
+#define NVREG_LINKSPEED_1000 50
NvRegUnknownSetupReg5 = 0x130,
#define NVREG_UNKSETUP5_BIT31 (1<<31)
- NvRegUnknownSetupReg3 = 0x134,
+ NvRegUnknownSetupReg3 = 0x13c,
#define NVREG_UNKSETUP3_VAL1 0x200010
NvRegTxRxControl = 0x144,
#define NVREG_TXRXCTL_KICK 0x0001
@@ -168,6 +184,7 @@ enum {
#define NVREG_TXRXCTL_BIT2 0x0004
#define NVREG_TXRXCTL_IDLE 0x0008
#define NVREG_TXRXCTL_RESET 0x0010
+#define NVREG_TXRXCTL_RXCHECK 0x0400
NvRegMIIStatus = 0x180,
#define NVREG_MIISTAT_ERROR 0x0001
#define NVREG_MIISTAT_LINKCHANGE 0x0008
@@ -179,15 +196,15 @@ enum {
NvRegAdapterControl = 0x188,
#define NVREG_ADAPTCTL_START 0x02
#define NVREG_ADAPTCTL_LINKUP 0x04
-#define NVREG_ADAPTCTL_PHYVALID 0x4000
+#define NVREG_ADAPTCTL_PHYVALID 0x40000
#define NVREG_ADAPTCTL_RUNNING 0x100000
#define NVREG_ADAPTCTL_PHYSHIFT 24
NvRegMIISpeed = 0x18c,
#define NVREG_MIISPEED_BIT8 (1<<8)
#define NVREG_MIIDELAY 5
NvRegMIIControl = 0x190,
-#define NVREG_MIICTL_INUSE 0x10000
-#define NVREG_MIICTL_WRITE 0x08000
+#define NVREG_MIICTL_INUSE 0x08000
+#define NVREG_MIICTL_WRITE 0x00400
#define NVREG_MIICTL_ADDRSHIFT 5
NvRegMIIData = 0x194,
NvRegWakeUpFlags = 0x200,
@@ -201,6 +218,7 @@ enum {
#define NVREG_WAKEUPFLAGS_ACCEPT_MAGPAT 0x01
#define NVREG_WAKEUPFLAGS_ACCEPT_WAKEUPPAT 0x02
#define NVREG_WAKEUPFLAGS_ACCEPT_LINKCHANGE 0x04
+#define NVREG_WAKEUPFLAGS_ENABLE 0x1111
NvRegPatternCRC = 0x204,
NvRegPatternMask = 0x208,
@@ -218,30 +236,61 @@ enum {
#define NVREG_POWERSTATE_D3 0x0003
};
-
-
-#define NV_TX_LASTPACKET (1<<0)
-#define NV_TX_RETRYERROR (1<<3)
-#define NV_TX_LASTPACKET1 (1<<8)
-#define NV_TX_DEFERRED (1<<10)
-#define NV_TX_CARRIERLOST (1<<11)
-#define NV_TX_LATECOLLISION (1<<12)
-#define NV_TX_UNDERFLOW (1<<13)
-#define NV_TX_ERROR (1<<14)
-#define NV_TX_VALID (1<<15)
-
-#define NV_RX_DESCRIPTORVALID (1<<0)
-#define NV_RX_MISSEDFRAME (1<<1)
-#define NV_RX_SUBSTRACT1 (1<<3)
-#define NV_RX_ERROR1 (1<<7)
-#define NV_RX_ERROR2 (1<<8)
-#define NV_RX_ERROR3 (1<<9)
-#define NV_RX_ERROR4 (1<<10)
-#define NV_RX_CRCERR (1<<11)
-#define NV_RX_OVERFLOW (1<<12)
-#define NV_RX_FRAMINGERR (1<<13)
-#define NV_RX_ERROR (1<<14)
-#define NV_RX_AVAIL (1<<15)
+#define FLAG_MASK_V1 0xffff0000
+#define FLAG_MASK_V2 0xffffc000
+#define LEN_MASK_V1 (0xffffffff ^ FLAG_MASK_V1)
+#define LEN_MASK_V2 (0xffffffff ^ FLAG_MASK_V2)
+
+#define NV_TX_LASTPACKET (1<<16)
+#define NV_TX_RETRYERROR (1<<19)
+#define NV_TX_LASTPACKET1 (1<<24)
+#define NV_TX_DEFERRED (1<<26)
+#define NV_TX_CARRIERLOST (1<<27)
+#define NV_TX_LATECOLLISION (1<<28)
+#define NV_TX_UNDERFLOW (1<<29)
+#define NV_TX_ERROR (1<<30)
+#define NV_TX_VALID (1<<31)
+
+#define NV_TX2_LASTPACKET (1<<29)
+#define NV_TX2_RETRYERROR (1<<18)
+#define NV_TX2_LASTPACKET1 (1<<23)
+#define NV_TX2_DEFERRED (1<<25)
+#define NV_TX2_CARRIERLOST (1<<26)
+#define NV_TX2_LATECOLLISION (1<<27)
+#define NV_TX2_UNDERFLOW (1<<28)
+/* error and valid are the same for both */
+#define NV_TX2_ERROR (1<<30)
+#define NV_TX2_VALID (1<<31)
+
+#define NV_RX_DESCRIPTORVALID (1<<16)
+#define NV_RX_MISSEDFRAME (1<<17)
+#define NV_RX_SUBSTRACT1 (1<<18)
+#define NV_RX_ERROR1 (1<<23)
+#define NV_RX_ERROR2 (1<<24)
+#define NV_RX_ERROR3 (1<<25)
+#define NV_RX_ERROR4 (1<<26)
+#define NV_RX_CRCERR (1<<27)
+#define NV_RX_OVERFLOW (1<<28)
+#define NV_RX_FRAMINGERR (1<<29)
+#define NV_RX_ERROR (1<<30)
+#define NV_RX_AVAIL (1<<31)
+
+#define NV_RX2_CHECKSUMMASK (0x1C000000)
+#define NV_RX2_CHECKSUMOK1 (0x10000000)
+#define NV_RX2_CHECKSUMOK2 (0x14000000)
+#define NV_RX2_CHECKSUMOK3 (0x18000000)
+#define NV_RX2_DESCRIPTORVALID (1<<29)
+#define NV_RX2_SUBSTRACT1 (1<<25)
+#define NV_RX2_ERROR1 (1<<18)
+#define NV_RX2_ERROR2 (1<<19)
+#define NV_RX2_ERROR3 (1<<20)
+#define NV_RX2_ERROR4 (1<<21)
+#define NV_RX2_CRCERR (1<<22)
+#define NV_RX2_OVERFLOW (1<<23)
+#define NV_RX2_FRAMINGERR (1<<24)
+/* error and avail are the same for both */
+#define NV_RX2_ERROR (1<<30)
+#define NV_RX2_AVAIL (1<<31)
/* Miscelaneous hardware related defines: */
#define NV_PCI_REGSZ 0x270
@@ -266,27 +315,73 @@ enum {
#define NV_WAKEUPMASKENTRIES 4
/* General driver defaults */
-#define NV_WATCHDOG_TIMEO (2*HZ)
-#define DEFAULT_MTU 1500 /* also maximum supported, at least for now */
+#define NV_WATCHDOG_TIMEO (5*HZ)
#define RX_RING 4
#define TX_RING 2
-/* limited to 1 packet until we understand NV_TX_LASTPACKET */
-#define TX_LIMIT_STOP 10
-#define TX_LIMIT_START 5
+
+/*
+ * If your nic mysteriously hangs then try to reduce the limits
+ * to 1/0: It might be required to set NV_TX_LASTPACKET in the
+ * last valid ring entry. But this would be impossible to
+ * implement - probably a disassembly error.
+ */
+#define TX_LIMIT_STOP 63
+#define TX_LIMIT_START 62
/* rx/tx mac addr + type + vlan + align + slack*/
-#define RX_NIC_BUFSIZE (DEFAULT_MTU + 64)
+#define RX_NIC_BUFSIZE (ETH_DATA_LEN + 64)
/* even more slack */
-#define RX_ALLOC_BUFSIZE (DEFAULT_MTU + 128)
+#define RX_ALLOC_BUFSIZE (ETH_DATA_LEN + 128)
#define OOM_REFILL (1+HZ/20)
#define POLL_WAIT (1+HZ/100)
-
+#define LINK_TIMEOUT (3*HZ)
+
+/*
+ * desc_ver values:
+ * This field has two purposes:
+ * - Newer nics uses a different ring layout. The layout is selected by
+ * comparing np->desc_ver with DESC_VER_xy.
+ * - It contains bits that are forced on when writing to NvRegTxRxControl.
+ */
+#define DESC_VER_1 0x0
+#define DESC_VER_2 (0x02100|NVREG_TXRXCTL_RXCHECK)
+
+/* PHY defines */
+#define PHY_OUI_MARVELL 0x5043
+#define PHY_OUI_CICADA 0x03f1
+#define PHYID1_OUI_MASK 0x03ff
+#define PHYID1_OUI_SHFT 6
+#define PHYID2_OUI_MASK 0xfc00
+#define PHYID2_OUI_SHFT 10
+#define PHY_INIT1 0x0f000
+#define PHY_INIT2 0x0e00
+#define PHY_INIT3 0x01000
+#define PHY_INIT4 0x0200
+#define PHY_INIT5 0x0004
+#define PHY_INIT6 0x02000
+#define PHY_GIGABIT 0x0100
+
+#define PHY_TIMEOUT 0x1
+#define PHY_ERROR 0x2
+
+#define PHY_100 0x1
+#define PHY_1000 0x2
+#define PHY_HALF 0x100
+
+/* FIXME: MII defines that should be added to <linux/mii.h> */
+#define MII_1000BT_CR 0x09
+#define MII_1000BT_SR 0x0a
+#define ADVERTISE_1000FULL 0x0200
+#define ADVERTISE_1000HALF 0x0100
+#define LPA_1000FULL 0x0800
+#define LPA_1000HALF 0x0400
+
+/* Big endian: should work, but is untested */
struct ring_desc {
u32 PacketBuffer;
- u16 Length;
- u16 Flags;
+ u32 FlagLen;
};
@@ -310,22 +405,25 @@ static struct forcedeth_private {
u32 linkspeed;
int duplex;
int phyaddr;
+ int wolenabled;
+ unsigned int phy_oui;
+ u16 gigabit;
/* General data: RO fields */
u8 *ring_addr;
u32 orig_mac[2];
u32 irqmask;
+ u32 desc_ver;
/* rx specific fields.
* Locking: Within irq hander or disable_irq+spin_lock(&np->lock);
*/
unsigned int cur_rx, refill_rx;
- unsigned int rx_buf_sz;
/*
* tx specific fields.
*/
unsigned int next_tx, nic_tx;
- u16 tx_flags;
+ u32 tx_flags;
} npx;
static struct forcedeth_private *np;
@@ -335,6 +433,13 @@ static inline void pci_push(u8 * base)
/* force out pending posted writes */
readl(base);
}
+
+static inline u32 nv_descr_getlength(struct ring_desc *prd, u32 v)
+{
+ return le32_to_cpu(prd->FlagLen)
+ & ((v == DESC_VER_1) ? LEN_MASK_V1 : LEN_MASK_V2);
+}
+
static int reg_delay(int offset, u32 mask,
u32 target, int delay, int delaymax, const char *msg)
{
@@ -383,18 +488,11 @@ static int mii_rw(struct nic *nic __unused, int addr, int miireg,
int value)
{
u8 *base = (u8 *) BASE;
- int was_running;
u32 reg;
int retval;
writel(NVREG_MIISTAT_MASK, base + NvRegMIIStatus);
- was_running = 0;
- reg = readl(base + NvRegAdapterControl);
- if (reg & NVREG_ADAPTCTL_RUNNING) {
- was_running = 1;
- writel(reg & ~NVREG_ADAPTCTL_RUNNING,
- base + NvRegAdapterControl);
- }
+
reg = readl(base + NvRegMIIControl);
if (reg & NVREG_MIICTL_INUSE) {
writel(NVREG_MIICTL_INUSE, base + NvRegMIIControl);
@@ -402,7 +500,7 @@ static int mii_rw(struct nic *nic __unused, int addr, int miireg,
}
reg =
- NVREG_MIICTL_INUSE | (addr << NVREG_MIICTL_ADDRSHIFT) | miireg;
+ (addr << NVREG_MIICTL_ADDRSHIFT) | miireg;
if (value != MII_READ) {
writel(value, base + NvRegMIIData);
reg |= NVREG_MIICTL_WRITE;
@@ -424,20 +522,123 @@ static int mii_rw(struct nic *nic __unused, int addr, int miireg,
miireg, addr));
retval = -1;
} else {
- /* FIXME: why is that required? */
- udelay(50);
retval = readl(base + NvRegMIIData);
dprintf(("mii_rw read from reg %d at PHY %d: 0x%x.\n",
miireg, addr, retval));
}
- if (was_running) {
- reg = readl(base + NvRegAdapterControl);
- writel(reg | NVREG_ADAPTCTL_RUNNING,
- base + NvRegAdapterControl);
- }
return retval;
}
+static int phy_reset(struct nic *nic)
+{
+
+ u32 miicontrol;
+ unsigned int tries = 0;
+
+ miicontrol = mii_rw(nic, np->phyaddr, MII_BMCR, MII_READ);
+ miicontrol |= BMCR_RESET;
+ if (mii_rw(nic, np->phyaddr, MII_BMCR, miicontrol)) {
+ return -1;
+ }
+
+ /* wait for 500ms */
+ mdelay(500);
+
+ /* must wait till reset is deasserted */
+ while (miicontrol & BMCR_RESET) {
+ mdelay(10);
+ miicontrol = mii_rw(nic, np->phyaddr, MII_BMCR, MII_READ);
+ /* FIXME: 100 tries seem excessive */
+ if (tries++ > 100)
+ return -1;
+ }
+ return 0;
+}
+
+static int phy_init(struct nic *nic)
+{
+ u8 *base = (u8 *) BASE;
+ u32 phyinterface, phy_reserved, mii_status, mii_control,
+ mii_control_1000, reg;
+
+ /* set advertise register */
+ reg = mii_rw(nic, np->phyaddr, MII_ADVERTISE, MII_READ);
+ reg |=
+ (ADVERTISE_10HALF | ADVERTISE_10FULL | ADVERTISE_100HALF |
+ ADVERTISE_100FULL | 0x800 | 0x400);
+ if (mii_rw(nic, np->phyaddr, MII_ADVERTISE, reg)) {
+ printf("phy write to advertise failed.\n");
+ return PHY_ERROR;
+ }
+
+ /* get phy interface type */
+ phyinterface = readl(base + NvRegPhyInterface);
+
+ /* see if gigabit phy */
+ mii_status = mii_rw(nic, np->phyaddr, MII_BMSR, MII_READ);
+
+ if (mii_status & PHY_GIGABIT) {
+ np->gigabit = PHY_GIGABIT;
+ mii_control_1000 =
+ mii_rw(nic, np->phyaddr, MII_1000BT_CR, MII_READ);
+ mii_control_1000 &= ~ADVERTISE_1000HALF;
+ if (phyinterface & PHY_RGMII)
+ mii_control_1000 |= ADVERTISE_1000FULL;
+ else
+ mii_control_1000 &= ~ADVERTISE_1000FULL;
+
+ if (mii_rw
+ (nic, np->phyaddr, MII_1000BT_CR, mii_control_1000)) {
+ printf("phy init failed.\n");
+ return PHY_ERROR;
+ }
+ } else
+ np->gigabit = 0;
+
+ /* reset the phy */
+ if (phy_reset(nic)) {
+ printf("phy reset failed\n");
+ return PHY_ERROR;
+ }
+
+ /* phy vendor specific configuration */
+ if ((np->phy_oui == PHY_OUI_CICADA) && (phyinterface & PHY_RGMII)) {
+ phy_reserved =
+ mii_rw(nic, np->phyaddr, MII_RESV1, MII_READ);
+ phy_reserved &= ~(PHY_INIT1 | PHY_INIT2);
+ phy_reserved |= (PHY_INIT3 | PHY_INIT4);
+ if (mii_rw(nic, np->phyaddr, MII_RESV1, phy_reserved)) {
+ printf("phy init failed.\n");
+ return PHY_ERROR;
+ }
+ phy_reserved =
+ mii_rw(nic, np->phyaddr, MII_NCONFIG, MII_READ);
+ phy_reserved |= PHY_INIT5;
+ if (mii_rw(nic, np->phyaddr, MII_NCONFIG, phy_reserved)) {
+ printf("phy init failed.\n");
+ return PHY_ERROR;
+ }
+ }
+ if (np->phy_oui == PHY_OUI_CICADA) {
+ phy_reserved =
+ mii_rw(nic, np->phyaddr, MII_SREVISION, MII_READ);
+ phy_reserved |= PHY_INIT6;
+ if (mii_rw(nic, np->phyaddr, MII_SREVISION, phy_reserved)) {
+ printf("phy init failed.\n");
+ return PHY_ERROR;
+ }
+ }
+
+ /* restart auto negotiation */
+ mii_control = mii_rw(nic, np->phyaddr, MII_BMCR, MII_READ);
+ mii_control |= (BMCR_ANRESTART | BMCR_ANENABLE);
+ if (mii_rw(nic, np->phyaddr, MII_BMCR, mii_control)) {
+ return PHY_ERROR;
+ }
+
+ return 0;
+}
+
static void start_rx(struct nic *nic __unused)
{
u8 *base = (u8 *) BASE;
@@ -497,11 +698,12 @@ static void txrx_reset(struct nic *nic __unused)
u8 *base = (u8 *) BASE;
dprintf(("txrx_reset\n"));
- writel(NVREG_TXRXCTL_BIT2 | NVREG_TXRXCTL_RESET,
+ writel(NVREG_TXRXCTL_BIT2 | NVREG_TXRXCTL_RESET | np->desc_ver,
base + NvRegTxRxControl);
+
pci_push(base);
udelay(NV_TXRX_RESET_DELAY);
- writel(NVREG_TXRXCTL_BIT2, base + NvRegTxRxControl);
+ writel(NVREG_TXRXCTL_BIT2 | np->desc_ver, base + NvRegTxRxControl);
pci_push(base);
}
@@ -519,9 +721,9 @@ static int alloc_rx(struct nic *nic __unused)
//int nr = refill_rx % RX_RING;
rx_ring[i].PacketBuffer =
virt_to_le32desc(&rxb[i * RX_NIC_BUFSIZE]);
- rx_ring[i].Length = cpu_to_le16(RX_NIC_BUFSIZE);
wmb();
- rx_ring[i].Flags = cpu_to_le16(NV_RX_AVAIL);
+ rx_ring[i].FlagLen =
+ cpu_to_le32(RX_NIC_BUFSIZE | NV_RX_AVAIL);
/* printf("alloc_rx: Packet %d marked as Available\n",
refill_rx); */
refill_rx++;
@@ -534,8 +736,67 @@ static int alloc_rx(struct nic *nic __unused)
static int update_linkspeed(struct nic *nic)
{
- int adv, lpa, newdup;
+ int adv, lpa;
u32 newls;
+ int newdup = np->duplex;
+ u32 mii_status;
+ int retval = 0;
+ u32 control_1000, status_1000, phyreg;
+ u8 *base = (u8 *) BASE;
+ int i;
+
+ /* BMSR_LSTATUS is latched, read it twice:
+ * we want the current value.
+ */
+ mii_rw(nic, np->phyaddr, MII_BMSR, MII_READ);
+ mii_status = mii_rw(nic, np->phyaddr, MII_BMSR, MII_READ);
+
+#if 1
+ //yhlu
+ for(i=0;i<30;i++) {
+ mii_status = mii_rw(nic, np->phyaddr, MII_BMSR, MII_READ);
+ if((mii_status & BMSR_LSTATUS) && (mii_status & BMSR_ANEGCOMPLETE)) break;
+ mdelay(100);
+ }
+#endif
+
+ if (!(mii_status & BMSR_LSTATUS)) {
+ printf
+ ("no link detected by phy - falling back to 10HD.\n");
+ newls = NVREG_LINKSPEED_FORCE | NVREG_LINKSPEED_10;
+ newdup = 0;
+ retval = 0;
+ goto set_speed;
+ }
+
+ /* check auto negotiation is complete */
+ if (!(mii_status & BMSR_ANEGCOMPLETE)) {
+ /* still in autonegotiation - configure nic for 10 MBit HD and wait. */
+ newls = NVREG_LINKSPEED_FORCE | NVREG_LINKSPEED_10;
+ newdup = 0;
+ retval = 0;
+ printf("autoneg not completed - falling back to 10HD.\n");
+ goto set_speed;
+ }
+
+ retval = 1;
+ if (np->gigabit == PHY_GIGABIT) {
+ control_1000 =
+ mii_rw(nic, np->phyaddr, MII_1000BT_CR, MII_READ);
+ status_1000 =
+ mii_rw(nic, np->phyaddr, MII_1000BT_SR, MII_READ);
+
+ if ((control_1000 & ADVERTISE_1000FULL) &&
+ (status_1000 & LPA_1000FULL)) {
+ printf
+ ("update_linkspeed: GBit ethernet detected.\n");
+ newls =
+ NVREG_LINKSPEED_FORCE | NVREG_LINKSPEED_1000;
+ newdup = 1;
+ goto set_speed;
+ }
+ }
+
adv = mii_rw(nic, np->phyaddr, MII_ADVERTISE, MII_READ);
lpa = mii_rw(nic, np->phyaddr, MII_LPA, MII_READ);
dprintf(("update_linkspeed: PHY advertises 0x%hX, lpa 0x%hX.\n",
@@ -560,30 +821,81 @@ static int update_linkspeed(struct nic *nic)
newls = NVREG_LINKSPEED_FORCE | NVREG_LINKSPEED_10;
newdup = 0;
}
- if (np->duplex != newdup || np->linkspeed != newls) {
- np->duplex = newdup;
- np->linkspeed = newls;
- return 1;
+
+ set_speed:
+ if (np->duplex == newdup && np->linkspeed == newls)
+ return retval;
+
+ dprintf(("changing link setting from %d/%s to %d/%s.\n",
+ np->linkspeed, np->duplex ? "Full-Duplex": "Half-Duplex", newls, newdup ? "Full-Duplex": "Half-Duplex"));
+
+ np->duplex = newdup;
+ np->linkspeed = newls;
+
+ if (np->gigabit == PHY_GIGABIT) {
+ phyreg = readl(base + NvRegRandomSeed);
+ phyreg &= ~(0x3FF00);
+ if ((np->linkspeed & 0xFFF) == NVREG_LINKSPEED_10)
+ phyreg |= NVREG_RNDSEED_FORCE3;
+ else if ((np->linkspeed & 0xFFF) == NVREG_LINKSPEED_100)
+ phyreg |= NVREG_RNDSEED_FORCE2;
+ else if ((np->linkspeed & 0xFFF) == NVREG_LINKSPEED_1000)
+ phyreg |= NVREG_RNDSEED_FORCE;
+ writel(phyreg, base + NvRegRandomSeed);
}
- return 0;
-}
+ phyreg = readl(base + NvRegPhyInterface);
+ phyreg &= ~(PHY_HALF | PHY_100 | PHY_1000);
+ if (np->duplex == 0)
+ phyreg |= PHY_HALF;
+ if ((np->linkspeed & 0xFFF) == NVREG_LINKSPEED_100)
+ phyreg |= PHY_100;
+ else if ((np->linkspeed & 0xFFF) == NVREG_LINKSPEED_1000)
+ phyreg |= PHY_1000;
+ writel(phyreg, base + NvRegPhyInterface);
+ writel(NVREG_MISC1_FORCE | (np->duplex ? 0 : NVREG_MISC1_HD),
+ base + NvRegMisc1);
+ pci_push(base);
+ writel(np->linkspeed, base + NvRegLinkSpeed);
+ pci_push(base);
+
+ return retval;
+}
+
+#if 0 /* Not used */
+static void nv_linkchange(struct nic *nic)
+{
+ if (update_linkspeed(nic)) {
+// if (netif_carrier_ok(nic)) {
+ stop_rx();
+//= } else {
+ // netif_carrier_on(dev);
+ // printk(KERN_INFO "%s: link up.\n", dev->name);
+ // }
+ start_rx(nic);
+ } else {
+ // if (netif_carrier_ok(dev)) {
+ // netif_carrier_off(dev);
+ // printk(KERN_INFO "%s: link down.\n", dev->name);
+ stop_rx();
+ // }
+ }
+}
+#endif
static int init_ring(struct nic *nic)
{
int i;
np->next_tx = np->nic_tx = 0;
- for (i = 0; i < TX_RING; i++) {
- tx_ring[i].Flags = 0;
- }
+ for (i = 0; i < TX_RING; i++)
+ tx_ring[i].FlagLen = 0;
np->cur_rx = 0;
np->refill_rx = 0;
- for (i = 0; i < RX_RING; i++) {
- rx_ring[i].Flags = 0;
- }
+ for (i = 0; i < RX_RING; i++)
+ rx_ring[i].FlagLen = 0;
return alloc_rx(nic);
}
@@ -637,15 +949,21 @@ static int forcedeth_reset(struct nic *nic)
writel(0, base + NvRegMulticastMaskA);
writel(0, base + NvRegMulticastMaskB);
writel(0, base + NvRegPacketFilterFlags);
+
+ writel(0, base + NvRegTransmitterControl);
+ writel(0, base + NvRegReceiverControl);
+
writel(0, base + NvRegAdapterControl);
+
+ /* 2) initialize descriptor rings */
+ oom = init_ring(nic);
+
writel(0, base + NvRegLinkSpeed);
writel(0, base + NvRegUnknownTransmitterReg);
txrx_reset(nic);
writel(0, base + NvRegUnknownSetupReg6);
- /* 2) initialize descriptor rings */
np->in_shutdown = 0;
- oom = init_ring(nic);
/* 3) set mac address */
{
@@ -661,51 +979,40 @@ static int forcedeth_reset(struct nic *nic)
writel(mac[1], base + NvRegMacAddrB);
}
- /* 4) continue setup */
+ /* 4) give hw rings */
+ writel((u32) virt_to_le32desc(&rx_ring[0]),
+ base + NvRegRxRingPhysAddr);
+ writel((u32) virt_to_le32desc(&tx_ring[0]),
+ base + NvRegTxRingPhysAddr);
+
+ writel(((RX_RING - 1) << NVREG_RINGSZ_RXSHIFT) +
+ ((TX_RING - 1) << NVREG_RINGSZ_TXSHIFT),
+ base + NvRegRingSizes);
+
+ /* 5) continue setup */
np->linkspeed = NVREG_LINKSPEED_FORCE | NVREG_LINKSPEED_10;
np->duplex = 0;
+ writel(np->linkspeed, base + NvRegLinkSpeed);
writel(NVREG_UNKSETUP3_VAL1, base + NvRegUnknownSetupReg3);
- writel(0, base + NvRegTxRxControl);
+ writel(np->desc_ver, base + NvRegTxRxControl);
pci_push(base);
- writel(NVREG_TXRXCTL_BIT1, base + NvRegTxRxControl);
-
+ writel(NVREG_TXRXCTL_BIT1 | np->desc_ver, base + NvRegTxRxControl);
reg_delay(NvRegUnknownSetupReg5, NVREG_UNKSETUP5_BIT31,
NVREG_UNKSETUP5_BIT31, NV_SETUP5_DELAY,
NV_SETUP5_DELAYMAX,
"open: SetupReg5, Bit 31 remained off\n");
- writel(0, base + NvRegUnknownSetupReg4);
-
- /* 5) Find a suitable PHY */
- writel(NVREG_MIISPEED_BIT8 | NVREG_MIIDELAY, base + NvRegMIISpeed);
- for (i = 1; i < 32; i++) {
- int id1, id2;
-
- id1 = mii_rw(nic, i, MII_PHYSID1, MII_READ);
- if (id1 < 0)
- continue;
- id2 = mii_rw(nic, i, MII_PHYSID2, MII_READ);
- if (id2 < 0)
- continue;
- dprintf(("open: Found PHY %04x:%04x at address %d.\n",
- id1, id2, i));
- np->phyaddr = i;
-
- update_linkspeed(nic);
-
- break;
- }
- if (i == 32) {
- printf("open: failing due to lack of suitable PHY.\n");
- ret = -1;
- goto out_drain;
- }
+ writel(0, base + NvRegUnknownSetupReg4);
+// writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus);
+ writel(NVREG_MIISTAT_MASK2, base + NvRegMIIStatus);
+#if 0
printf("%d-Mbs Link, %s-Duplex\n",
np->linkspeed & NVREG_LINKSPEED_10 ? 10 : 100,
np->duplex ? "Full" : "Half");
+#endif
+
/* 6) continue setup */
- writel(NVREG_MISC1_FORCE | (np->duplex ? 0 : NVREG_MISC1_HD),
- base + NvRegMisc1);
+ writel(NVREG_MISC1_FORCE | NVREG_MISC1_HD, base + NvRegMisc1);
writel(readl(base + NvRegTransmitterStatus),
base + NvRegTransmitterStatus);
writel(NVREG_PFF_ALWAYS, base + NvRegPacketFilterFlags);
@@ -714,8 +1021,8 @@ static int forcedeth_reset(struct nic *nic)
writel(readl(base + NvRegReceiverStatus),
base + NvRegReceiverStatus);
- /* FIXME: I cheated and used the calculator to get a random number */
- i = 75963081;
+ /* Get a random number */
+ i = random();
writel(NVREG_RNDSEED_FORCE | (i & NVREG_RNDSEED_MASK),
base + NvRegRandomSeed);
writel(NVREG_UNKSETUP1_VAL, base + NvRegUnknownSetupReg1);
@@ -724,36 +1031,24 @@ static int forcedeth_reset(struct nic *nic)
writel(NVREG_UNKSETUP6_VAL, base + NvRegUnknownSetupReg6);
writel((np->
phyaddr << NVREG_ADAPTCTL_PHYSHIFT) |
- NVREG_ADAPTCTL_PHYVALID, base + NvRegAdapterControl);
+ NVREG_ADAPTCTL_PHYVALID | NVREG_ADAPTCTL_RUNNING,
+ base + NvRegAdapterControl);
+ writel(NVREG_MIISPEED_BIT8 | NVREG_MIIDELAY, base + NvRegMIISpeed);
writel(NVREG_UNKSETUP4_VAL, base + NvRegUnknownSetupReg4);
writel(NVREG_WAKEUPFLAGS_VAL, base + NvRegWakeUpFlags);
- /* 7) start packet processing */
- writel((u32) virt_to_le32desc(&rx_ring[0]),
- base + NvRegRxRingPhysAddr);
- writel((u32) virt_to_le32desc(&tx_ring[0]),
- base + NvRegTxRingPhysAddr);
-
-
- writel(((RX_RING - 1) << NVREG_RINGSZ_RXSHIFT) +
- ((TX_RING - 1) << NVREG_RINGSZ_TXSHIFT),
- base + NvRegRingSizes);
-
i = readl(base + NvRegPowerState);
- if ((i & NVREG_POWERSTATE_POWEREDUP) == 0) {
+ if ((i & NVREG_POWERSTATE_POWEREDUP) == 0)
writel(NVREG_POWERSTATE_POWEREDUP | i,
base + NvRegPowerState);
- }
+
pci_push(base);
udelay(10);
writel(readl(base + NvRegPowerState) | NVREG_POWERSTATE_VALID,
base + NvRegPowerState);
- writel(NVREG_ADAPTCTL_RUNNING, base + NvRegAdapterControl);
writel(0, base + NvRegIrqMask);
pci_push(base);
- writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus);
- pci_push(base);
writel(NVREG_MIISTAT_MASK2, base + NvRegMIIStatus);
writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus);
pci_push(base);
@@ -768,22 +1063,32 @@ static int forcedeth_reset(struct nic *nic)
base + NvRegPacketFilterFlags);
set_multicast(nic);
+ /* One manual link speed update: Interrupts are enabled, future link
+ * speed changes cause interrupts and are handled by nv_link_irq().
+ */
+ {
+ u32 miistat;
+ miistat = readl(base + NvRegMIIStatus);
+ writel(NVREG_MIISTAT_MASK, base + NvRegMIIStatus);
+ dprintf(("startup: got 0x%hX.\n", miistat));
+ }
+ ret = update_linkspeed(nic);
+
//start_rx(nic);
start_tx(nic);
- if (!
- (mii_rw(nic, np->phyaddr, MII_BMSR, MII_READ) &
- BMSR_ANEGCOMPLETE)) {
+ if (ret) {
+ //Start Connection netif_carrier_on(dev);
+ } else {
printf("no link during initialization.\n");
}
- udelay(10000);
- out_drain:
return ret;
}
-//extern void hex_dump(const char *data, const unsigned int len);
-
+/*
+ * extern void hex_dump(const char *data, const unsigned int len);
+*/
/**************************************************************************
POLL - Wait for a frame
***************************************************************************/
@@ -793,26 +1098,35 @@ static int forcedeth_poll(struct nic *nic, int retrieve)
/* nic->packet should contain data on return */
/* nic->packetlen should contain length of data */
- struct ring_desc *prd;
int len;
int i;
+ u32 Flags;
i = np->cur_rx % RX_RING;
- prd = &rx_ring[i];
- if ( ! (prd->Flags & cpu_to_le16(NV_RX_DESCRIPTORVALID)) ) {
- return 0;
+ Flags = le32_to_cpu(rx_ring[i].FlagLen);
+ len = nv_descr_getlength(&rx_ring[i], np->desc_ver);
+
+ if (Flags & NV_RX_AVAIL)
+ return 0; /* still owned by hardware, */
+
+ if (np->desc_ver == DESC_VER_1) {
+ if (!(Flags & NV_RX_DESCRIPTORVALID))
+ return 0;
+ } else {
+ if (!(Flags & NV_RX2_DESCRIPTORVALID))
+ return 0;
}
- if ( ! retrieve ) return 1;
+ if (!retrieve)
+ return 1;
/* got a valid packet - forward it to the network core */
- len = cpu_to_le16(prd->Length);
nic->packetlen = len;
- //hex_dump(rxb + (i * RX_NIC_BUFSIZE), len);
- memcpy(nic->packet, rxb +
- (i * RX_NIC_BUFSIZE), nic->packetlen);
-
+ memcpy(nic->packet, rxb + (i * RX_NIC_BUFSIZE), nic->packetlen);
+/*
+ * hex_dump(rxb + (i * RX_NIC_BUFSIZE), len);
+*/
wmb();
np->cur_rx++;
alloc_rx(nic);
@@ -831,7 +1145,6 @@ static void forcedeth_transmit(struct nic *nic, const char *d, /* Destination */
/* send the packet to destination */
u8 *ptxb;
u16 nstype;
- //u16 status;
u8 *base = (u8 *) BASE;
int nr = np->next_tx % TX_RING;
@@ -851,14 +1164,12 @@ static void forcedeth_transmit(struct nic *nic, const char *d, /* Destination */
ptxb[s++] = '\0';
tx_ring[nr].PacketBuffer = (u32) virt_to_le32desc(ptxb);
- tx_ring[nr].Length = cpu_to_le16(s - 1);
wmb();
- tx_ring[nr].Flags = np->tx_flags;
+ tx_ring[nr].FlagLen = cpu_to_le32((s - 1) | np->tx_flags);
- writel(NVREG_TXRXCTL_KICK, base + NvRegTxRxControl);
+ writel(NVREG_TXRXCTL_KICK | np->desc_ver, base + NvRegTxRxControl);
pci_push(base);
- tx_ring[nr].Flags = np->tx_flags;
np->next_tx++;
}
@@ -896,16 +1207,17 @@ static void forcedeth_disable ( struct nic *nic __unused ) {
/**************************************************************************
IRQ - Enable, Disable, or Force interrupts
***************************************************************************/
-static void forcedeth_irq(struct nic *nic __unused, irq_action_t action __unused)
+static void forcedeth_irq(struct nic *nic __unused,
+ irq_action_t action __unused)
{
- switch ( action ) {
- case DISABLE :
- break;
- case ENABLE :
- break;
- case FORCE :
- break;
- }
+ switch (action) {
+ case DISABLE:
+ break;
+ case ENABLE:
+ break;
+ case FORCE:
+ break;
+ }
}
static struct nic_operations forcedeth_operations = {
@@ -916,14 +1228,6 @@ static struct nic_operations forcedeth_operations = {
};
-static struct pci_id forcedeth_nics[] = {
- PCI_ROM(0x10de, 0x01C3, "nforce", "nForce Ethernet Controller"),
- PCI_ROM(0x10de, 0x0066, "nforce2", "nForce2 Ethernet Controller"),
- PCI_ROM(0x10de, 0x00D6, "nforce3", "nForce3 Ethernet Controller"),
-};
-
-PCI_DRIVER ( forcedeth_driver, forcedeth_nics, PCI_NO_CLASS );
-
/**************************************************************************
PROBE - Look for an adapter, this routine's visible to the outside
***************************************************************************/
@@ -935,6 +1239,7 @@ static int forcedeth_probe ( struct nic *nic, struct pci_device *pci ) {
unsigned long addr;
int sz;
u8 *base;
+ int i;
if (pci->ioaddr == 0)
return 0;
@@ -956,6 +1261,15 @@ static int forcedeth_probe ( struct nic *nic, struct pci_device *pci ) {
BASE = (unsigned long) ioremap(addr, sz);
if (!BASE)
return 0;
+
+ /* handle different descriptor versions */
+ if (pci->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_1 ||
+ pci->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_2 ||
+ pci->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_3)
+ np->desc_ver = DESC_VER_1;
+ else
+ np->desc_ver = DESC_VER_2;
+
//rx_ring[0] = rx_ring;
//tx_ring[0] = tx_ring;
@@ -992,36 +1306,121 @@ static int forcedeth_probe ( struct nic *nic, struct pci_device *pci ) {
#endif
printf("%s: MAC Address %!, ", pci->name, nic->node_addr);
- np->tx_flags =
- cpu_to_le16(NV_TX_LASTPACKET | NV_TX_LASTPACKET1 |
- NV_TX_VALID);
- switch (pci->device_id) {
- case 0x01C3: // nforce
- np->irqmask = NVREG_IRQMASK_WANTED_2;
- np->irqmask |= NVREG_IRQ_TIMER;
- break;
- case 0x0066: // nforce2
- np->tx_flags |= cpu_to_le16(NV_TX_LASTPACKET1);
- np->irqmask = NVREG_IRQMASK_WANTED_2;
- np->irqmask |= NVREG_IRQ_TIMER;
- break;
- case 0x00D6: // nforce3
- np->tx_flags |= cpu_to_le16(NV_TX_LASTPACKET1);
- np->irqmask = NVREG_IRQMASK_WANTED_2;
- np->irqmask |= NVREG_IRQ_TIMER;
-
- }
+ /* disable WOL */
+ writel(0, base + NvRegWakeUpFlags);
+ np->wolenabled = 0;
+
+ if (np->desc_ver == DESC_VER_1) {
+ np->tx_flags = NV_TX_LASTPACKET | NV_TX_VALID;
+ } else {
+ np->tx_flags = NV_TX2_LASTPACKET | NV_TX2_VALID;
+ }
+
+ switch (pci->device_id) {
+ case 0x01C3: // nforce
+ // DEV_IRQMASK_1|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
+ np->irqmask = NVREG_IRQMASK_WANTED_2 | NVREG_IRQ_TIMER;
+ // np->need_linktimer = 1;
+ // np->link_timeout = jiffies + LINK_TIMEOUT;
+ break;
+ case 0x0066:
+ /* Fall Through */
+ case 0x00D6:
+ // DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER
+ np->irqmask = NVREG_IRQMASK_WANTED_2;
+ np->irqmask |= NVREG_IRQ_TIMER;
+ // np->need_linktimer = 1;
+ // np->link_timeout = jiffies + LINK_TIMEOUT;
+ if (np->desc_ver == DESC_VER_1)
+ np->tx_flags |= NV_TX_LASTPACKET1;
+ else
+ np->tx_flags |= NV_TX2_LASTPACKET1;
+ break;
+ case 0x0086:
+ /* Fall Through */
+ case 0x008c:
+ /* Fall Through */
+ case 0x00e6:
+ /* Fall Through */
+ case 0x00df:
+ /* Fall Through */
+ case 0x0056:
+ /* Fall Through */
+ case 0x0057:
+ /* Fall Through */
+ case 0x0037:
+ /* Fall Through */
+ case 0x0038:
+ //DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ
+ np->irqmask = NVREG_IRQMASK_WANTED_2;
+ np->irqmask |= NVREG_IRQ_TIMER;
+ // np->need_linktimer = 1;
+ // np->link_timeout = jiffies + LINK_TIMEOUT;
+ if (np->desc_ver == DESC_VER_1)
+ np->tx_flags |= NV_TX_LASTPACKET1;
+ else
+ np->tx_flags |= NV_TX2_LASTPACKET1;
+ break;
+ default:
+ printf
+ ("Your card was undefined in this driver. Review driver_data in Linux driver and send a patch\n");
+ }
+
+ /* find a suitable phy */
+ for (i = 1; i < 32; i++) {
+ int id1, id2;
+ id1 = mii_rw(nic, i, MII_PHYSID1, MII_READ);
+ if (id1 < 0 || id1 == 0xffff)
+ continue;
+ id2 = mii_rw(nic, i, MII_PHYSID2, MII_READ);
+ if (id2 < 0 || id2 == 0xffff)
+ continue;
+ id1 = (id1 & PHYID1_OUI_MASK) << PHYID1_OUI_SHFT;
+ id2 = (id2 & PHYID2_OUI_MASK) >> PHYID2_OUI_SHFT;
+ dprintf
+ (("%s: open: Found PHY %hX:%hX at address %d.\n",
+ pci->name, id1, id2, i));
+ np->phyaddr = i;
+ np->phy_oui = id1 | id2;
+ break;
+ }
+ if (i == 32) {
+ /* PHY in isolate mode? No phy attached and user wants to
+ * test loopback? Very odd, but can be correct.
+ */
+ printf
+ ("%s: open: Could not find a valid PHY.\n", pci->name);
+ }
+
+ if (i != 32) {
+ /* reset it */
+ phy_init(nic);
+ }
+
dprintf(("%s: forcedeth.c: subsystem: %hX:%hX bound to %s\n",
pci->name, pci->vendor, pci->dev_id, pci->name));
+ if(!forcedeth_reset(nic)) return 0; // no valid link
- forcedeth_reset(nic);
-// if (board_found && valid_link)
/* point to NIC specific routines */
nic->nic_op = &forcedeth_operations;
return 1;
-// }
- /* else */
}
+static struct pci_id forcedeth_nics[] = {
+PCI_ROM(0x10de, 0x01C3, "nforce", "nForce NVENET_1 Ethernet Controller"),
+PCI_ROM(0x10de, 0x0066, "nforce2", "nForce NVENET_2 Ethernet Controller"),
+PCI_ROM(0x10de, 0x00D6, "nforce3", "nForce NVENET_3 Ethernet Controller"),
+PCI_ROM(0x10de, 0x0086, "nforce4", "nForce NVENET_4 Ethernet Controller"),
+PCI_ROM(0x10de, 0x008c, "nforce5", "nForce NVENET_5 Ethernet Controller"),
+PCI_ROM(0x10de, 0x00e6, "nforce6", "nForce NVENET_6 Ethernet Controller"),
+PCI_ROM(0x10de, 0x00df, "nforce7", "nForce NVENET_7 Ethernet Controller"),
+PCI_ROM(0x10de, 0x0056, "nforce8", "nForce NVENET_8 Ethernet Controller"),
+PCI_ROM(0x10de, 0x0057, "nforce9", "nForce NVENET_9 Ethernet Controller"),
+PCI_ROM(0x10de, 0x0037, "nforce10", "nForce NVENET_10 Ethernet Controller"),
+PCI_ROM(0x10de, 0x0038, "nforce11", "nForce NVENET_11 Ethernet Controller"),
+};
+
+PCI_DRIVER ( forcedeth_driver, forcedeth_nics, PCI_NO_CLASS );
+
DRIVER ( "forcedeth", nic_driver, pci_driver, forcedeth_driver,
forcedeth_probe, forcedeth_disable );
diff --git a/src/drivers/net/mlx_ipoib/MT23108_PRM.h b/src/drivers/net/mlx_ipoib/MT23108_PRM.h
new file mode 100644
index 000000000..646e94e40
--- /dev/null
+++ b/src/drivers/net/mlx_ipoib/MT23108_PRM.h
@@ -0,0 +1,2800 @@
+/*
+ This software is available to you under a choice of one of two
+ licenses. You may choose to be licensed under the terms of the GNU
+ General Public License (GPL) Version 2, available at
+ <http://www.fsf.org/copyleft/gpl.html>, or the OpenIB.org BSD
+ license, available in the LICENSE.TXT file accompanying this
+ software. These details are also available at
+ <http://openib.org/license.html>.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+
+ Copyright (c) 2004 Mellanox Technologies Ltd. All rights reserved.
+*/
+
+/***
+ *** This file was generated at "Tue Sep 6 09:14:00 2005"
+ *** by:
+ *** % csp_bf -copyright=/mswg/misc/license-header.txt -prefix tavorprm_ -bits -fixnames MT23108_PRM.csp
+ ***/
+
+#ifndef H_prefix_tavorprm_bits_fixnames_MT23108_PRM_csp_H
+#define H_prefix_tavorprm_bits_fixnames_MT23108_PRM_csp_H
+
+#include "bit_ops.h"
+
+/* Send doorbell */
+
+struct tavorprm_send_doorbell_st { /* Little Endian */
+ pseudo_bit_t nopcode[0x00005]; /* Opcode of descriptor to be executed */
+ pseudo_bit_t f[0x00001]; /* Fence bit. If set, descriptor is fenced */
+ pseudo_bit_t nda[0x0001a]; /* Bits 31:6 of descriptors virtual address */
+/* -------------- */
+ pseudo_bit_t nds[0x00006]; /* Next descriptor size (in 16-byte chunks) */
+ pseudo_bit_t reserved0[0x00002];
+ pseudo_bit_t qpn[0x00018]; /* QP number this doorbell is rung on */
+/* -------------- */
+};
+
+/* ACCESS_DDR_inject_errors_input_modifier */
+
+struct tavorprm_access_ddr_inject_errors_input_modifier_st { /* Little Endian */
+ pseudo_bit_t index3[0x00007];
+ pseudo_bit_t q3[0x00001];
+ pseudo_bit_t index2[0x00007];
+ pseudo_bit_t q2[0x00001];
+ pseudo_bit_t index1[0x00007];
+ pseudo_bit_t q1[0x00001];
+ pseudo_bit_t index0[0x00007];
+ pseudo_bit_t q0[0x00001];
+/* -------------- */
+};
+
+/* ACCESS_DDR_inject_errors_input_parameter */
+
+struct tavorprm_access_ddr_inject_errors_input_parameter_st { /* Little Endian */
+ pseudo_bit_t ba[0x00002]; /* Bank Address */
+ pseudo_bit_t da[0x00002]; /* Dimm Address */
+ pseudo_bit_t reserved0[0x0001c];
+/* -------------- */
+ pseudo_bit_t ra[0x00010]; /* Row Address */
+ pseudo_bit_t ca[0x00010]; /* Column Address */
+/* -------------- */
+};
+
+/* Address Path */
+
+struct tavorprm_address_path_st { /* Little Endian */
+ pseudo_bit_t pkey_index[0x00007]; /* PKey table index */
+ pseudo_bit_t reserved0[0x00011];
+ pseudo_bit_t port_number[0x00002]; /* Specific port associated with this QP/EE.
+ 1 - Port 1
+ 2 - Port 2
+ other - reserved */
+ pseudo_bit_t reserved1[0x00006];
+/* -------------- */
+ pseudo_bit_t rlid[0x00010]; /* Remote (Destination) LID */
+ pseudo_bit_t my_lid_path_bits[0x00007];/* Source LID - the lower 7 bits (upper bits are taken from PortInfo) */
+ pseudo_bit_t g[0x00001]; /* Global address enable - if set, GRH will be formed for packet header */
+ pseudo_bit_t reserved2[0x00005];
+ pseudo_bit_t rnr_retry[0x00003]; /* RNR retry count (see C9-132 in IB spec Vol 1)
+ 0-6 - number of retries
+ 7 - infinite */
+/* -------------- */
+ pseudo_bit_t hop_limit[0x00008]; /* IPv6 hop limit */
+ pseudo_bit_t max_stat_rate[0x00003];/* Maximum static rate control.
+ 0 - 4X injection rate
+ 1 - 1X injection rate
+ other - reserved
+ */
+ pseudo_bit_t reserved3[0x00005];
+ pseudo_bit_t mgid_index[0x00006]; /* Index to port GID table */
+ pseudo_bit_t reserved4[0x00005];
+ pseudo_bit_t ack_timeout[0x00005]; /* Local ACK timeout - Transport timer for activation of retransmission mechanism. Refer to IB spec Vol1 9.7.6.1.3 for further details.
+ The transport timer is set to 4.096us*2^ack_timeout, if ack_timeout is 0 then transport timer is disabled. */
+/* -------------- */
+ pseudo_bit_t flow_label[0x00014]; /* IPv6 flow label */
+ pseudo_bit_t tclass[0x00008]; /* IPv6 TClass */
+ pseudo_bit_t sl[0x00004]; /* InfiniBand Service Level (SL) */
+/* -------------- */
+ pseudo_bit_t rgid_127_96[0x00020]; /* Remote GID[127:96] */
+/* -------------- */
+ pseudo_bit_t rgid_95_64[0x00020]; /* Remote GID[95:64] */
+/* -------------- */
+ pseudo_bit_t rgid_63_32[0x00020]; /* Remote GID[63:32] */
+/* -------------- */
+ pseudo_bit_t rgid_31_0[0x00020]; /* Remote GID[31:0] */
+/* -------------- */
+};
+
+/* HCA Command Register (HCR) */
+
+struct tavorprm_hca_command_register_st { /* Little Endian */
+ pseudo_bit_t in_param_h[0x00020]; /* Input Parameter: parameter[63:32] or pointer[63:32] to input mailbox (see command description) */
+/* -------------- */
+ pseudo_bit_t in_param_l[0x00020]; /* Input Parameter: parameter[31:0] or pointer[31:0] to input mailbox (see command description) */
+/* -------------- */
+ pseudo_bit_t input_modifier[0x00020];/* Input Parameter Modifier */
+/* -------------- */
+ pseudo_bit_t out_param_h[0x00020]; /* Output Parameter: parameter[63:32] or pointer[63:32] to output mailbox (see command description) */
+/* -------------- */
+ pseudo_bit_t out_param_l[0x00020]; /* Output Parameter: parameter[31:0] or pointer[31:0] to output mailbox (see command description) */
+/* -------------- */
+ pseudo_bit_t reserved0[0x00010];
+ pseudo_bit_t token[0x00010]; /* Software assigned token to the command, to uniquely identify it. The token is returned to the software in the EQE reported. */
+/* -------------- */
+ pseudo_bit_t opcode[0x0000c]; /* Command opcode */
+ pseudo_bit_t opcode_modifier[0x00004];/* Opcode Modifier, see specific description for each command. */
+ pseudo_bit_t reserved1[0x00006];
+ pseudo_bit_t e[0x00001]; /* Event Request
+ 0 - Don't report event (software will poll the GO bit)
+ 1 - Report event to EQ when the command completes */
+ pseudo_bit_t go[0x00001]; /* Go (0=Software ownership for the HCR, 1=Hardware ownership for the HCR)
+ Software can write to the HCR only if Go bit is cleared.
+ Software must set the Go bit to trigger the HW to execute the command. Software must not write to this register value other than 1 for the Go bit. */
+ pseudo_bit_t status[0x00008]; /* Command execution status report. Valid only if command interface in under SW ownership (Go bit is cleared)
+ 0 - command completed without error. If different than zero, command execution completed with error. Syndrom encoding is depended on command executed and is defined for each command */
+/* -------------- */
+};
+
+/* EQ Doorbell */
+
+struct tavorprm_eq_cmd_doorbell_st { /* Little Endian */
+ pseudo_bit_t eqn[0x00006]; /* EQ accessed */
+ pseudo_bit_t reserved0[0x00012];
+ pseudo_bit_t eq_cmd[0x00008]; /* Command to be executed on EQ
+ 01 - increment Consumer_indx by one
+ 02 - Request notification for next event (Arm EQ)
+ 03 - Disarm CQ (CQ number is specified in EQ_param)
+ 04 - set Consumer_indx to value of EQ_param
+ 05 - move EQ to Always Armed state
+ other - reserved */
+/* -------------- */
+ pseudo_bit_t eq_param[0x00020]; /* parameter to be used by EQ commands 03 and 04. Reserved for other commands. */
+/* -------------- */
+};
+
+/* CQ Doorbell */
+
+struct tavorprm_cq_cmd_doorbell_st { /* Little Endian */
+ pseudo_bit_t cqn[0x00018]; /* CQ number accessed */
+ pseudo_bit_t cq_cmd[0x00008]; /* Command to be executed on CQ
+ 01 - Increment Consumer_indx by cq_param plus 1
+ 02 - Request notification for next Solicited or Unsolicited completion event. CQ_param must contain last succesfully polled consumer index. For newly generated CQs the CQ_param should contain (initial consumer index-1) modulu CQ size. When working with CQs with overrun detection, CQ_param can be set to 0xFFFFFFFF (HW will use the last polled index).
+ 03 - Request notification for next Solicited completion event CQ_param must contain last succesfully polled consumer index. For newly generated CQs the CQ_param should contain (initial consumer index-1) modulu CQ size. When working with CQs with overrun detection, CQ_param can be set to 0xFFFFFFFF (HW will use the last polled index).
+ 04 - Set Consumer_indx to value of CQ_param
+ 05 - Request notification for multiple completions (see Advanced Topics chater)
+ other - reserved */
+/* -------------- */
+ pseudo_bit_t cq_param[0x00020]; /* parameter to be used by CQ command */
+/* -------------- */
+};
+
+/* Receive doorbell */
+
+struct tavorprm_receive_doorbell_st { /* Little Endian */
+ pseudo_bit_t nds[0x00006]; /* Next descriptor size (in 16-byte chunks)
+ Must be zero for SRQ doorbells */
+ pseudo_bit_t nda[0x0001a]; /* Bits 31:6 of descriptors virtual address */
+/* -------------- */
+ pseudo_bit_t credits[0x00008]; /* Amount of credits ((length of the chain) posted with the doorbell on receive queue. Chain of up to 256 descriptors can be linked with single doorbell. Zero value in this field means 256. */
+ pseudo_bit_t qpn[0x00018]; /* QP number or SRQ number this doorbell is rung on */
+/* -------------- */
+};
+
+/* RD-send doorbell */
+
+struct tavorprm_rd_send_doorbell_st { /* Little Endian */
+ pseudo_bit_t reserved0[0x00008];
+ pseudo_bit_t een[0x00018]; /* End-to-end context number (reliable datagram)
+ Must be zero for Nop and Bind operations */
+/* -------------- */
+ pseudo_bit_t reserved1[0x00008];
+ pseudo_bit_t qpn[0x00018]; /* QP number this doorbell is rung on */
+/* -------------- */
+ struct tavorprm_send_doorbell_st snd_params;/* Send parameters */
+/* -------------- */
+};
+
+/* Multicast Group Member QP */
+
+struct tavorprm_mgmqp_st { /* Little Endian */
+ pseudo_bit_t qpn_i[0x00018]; /* QPN_i: QP number which is a member in this multicast group. Valid only if Qi bit is set. Length of the QPN_i list is set in INIT_HCA */
+ pseudo_bit_t reserved0[0x00007];
+ pseudo_bit_t qi[0x00001]; /* Qi: QPN_i is valid */
+/* -------------- */
+};
+
+/* vsd */
+
+struct tavorprm_vsd_st { /* Little Endian */
+ pseudo_bit_t vsd_dw0[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw1[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw2[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw3[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw4[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw5[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw6[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw7[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw8[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw9[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw10[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw11[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw12[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw13[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw14[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw15[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw16[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw17[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw18[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw19[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw20[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw21[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw22[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw23[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw24[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw25[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw26[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw27[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw28[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw29[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw30[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw31[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw32[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw33[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw34[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw35[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw36[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw37[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw38[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw39[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw40[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw41[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw42[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw43[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw44[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw45[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw46[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw47[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw48[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw49[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw50[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw51[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw52[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw53[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw54[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw55[0x00020];
+/* -------------- */
+};
+
+/* ACCESS_DDR_inject_errors */
+
+struct tavorprm_access_ddr_inject_errors_st { /* Little Endian */
+ struct tavorprm_access_ddr_inject_errors_input_parameter_st access_ddr_inject_errors_input_parameter;
+/* -------------- */
+ struct tavorprm_access_ddr_inject_errors_input_modifier_st access_ddr_inject_errors_input_modifier;
+/* -------------- */
+ pseudo_bit_t reserved0[0x00020];
+/* -------------- */
+};
+
+/* Logical DIMM Information */
+
+struct tavorprm_dimminfo_st { /* Little Endian */
+ pseudo_bit_t dimmsize[0x00010]; /* Size of DIMM in units of 2^20 Bytes. This value is valid only when DIMMStatus is 0. */
+ pseudo_bit_t reserved0[0x00008];
+ pseudo_bit_t dimmstatus[0x00001]; /* DIMM Status
+ 0 - Enabled
+ 1 - Disabled
+ */
+ pseudo_bit_t dh[0x00001]; /* When set, the DIMM is Hidden and can not be accessed from the PCI bus. */
+ pseudo_bit_t wo[0x00001]; /* When set, the DIMM is write only.
+ If data integrity is configured (other than none), the DIMM must be
+ only targeted by write transactions where the address and size are multiples of 16 bytes. */
+ pseudo_bit_t reserved1[0x00005];
+/* -------------- */
+ pseudo_bit_t spd[0x00001]; /* 0 - DIMM SPD was read from DIMM
+ 1 - DIMM SPD was read from InfiniHost NVMEM */
+ pseudo_bit_t sladr[0x00003]; /* SPD Slave Address 3 LSBits.
+ Valid only if spd bit is 0. */
+ pseudo_bit_t sock_num[0x00002]; /* DIMM socket number (for double sided DIMM one of the two numbers will be reported) */
+ pseudo_bit_t syn[0x00004]; /* Error syndrome (valid regardless of status value)
+ 0 - DIMM has no error
+ 1 - SPD error (e.g. checksum error, no response, error while reading)
+ 2 - DIMM out of bounds (e.g. DIMM rows number is not between 7 and 14, DIMM type is not 2)
+ 3 - DIMM conflict (e.g. mix of registered and unbuffered DIMMs, CAS latency conflict)
+ 5 - DIMM size trimmed due to configuration (size exceeds)
+ other - Error, reserved
+ */
+ pseudo_bit_t reserved2[0x00016];
+/* -------------- */
+ pseudo_bit_t vendor_id_h[0x00020]; /* JDEC Manufacturer ID[63:32] */
+/* -------------- */
+ pseudo_bit_t vendor_id_l[0x00020]; /* JDEC Manufacturer ID[31:0] */
+/* -------------- */
+ pseudo_bit_t dimm_start_adr_h[0x00020];/* DIMM memory start address [63:32]. This value is valid only when DIMMStatus is 0. */
+/* -------------- */
+ pseudo_bit_t dimm_start_adr_l[0x00020];/* DIMM memory start address [31:0]. This value is valid only when DIMMStatus is 0. */
+/* -------------- */
+ pseudo_bit_t reserved3[0x00040];
+/* -------------- */
+};
+
+/* UAR Parameters */
+
+struct tavorprm_uar_params_st { /* Little Endian */
+ pseudo_bit_t uar_base_addr_h[0x00020];/* UAR Base Address [63:32] (QUERY_HCA only) */
+/* -------------- */
+ pseudo_bit_t reserved0[0x00014];
+ pseudo_bit_t uar_base_addr_l[0x0000c];/* UAR Base Address [31:20] (QUERY_HCA only) */
+/* -------------- */
+ pseudo_bit_t uar_page_sz[0x00008]; /* This field defines the size of each UAR page.
+ Size of UAR Page is 4KB*2^UAR_Page_Size */
+ pseudo_bit_t reserved1[0x00018];
+/* -------------- */
+ pseudo_bit_t reserved2[0x00020];
+/* -------------- */
+ pseudo_bit_t uar_scratch_base_addr_h[0x00020];/* Base address of UAR scratchpad [63:32].
+ Number of entries in table is UAR BAR size divided by UAR Page Size.
+ Table must be aligned to entry size. */
+/* -------------- */
+ pseudo_bit_t uar_scratch_base_addr_l[0x00020];/* Base address of UAR scratchpad [31:0].
+ Number of entries in table is UAR BAR size divided by UAR Page Size.
+ Table must be aligned to entry size. */
+/* -------------- */
+ pseudo_bit_t reserved3[0x00040];
+/* -------------- */
+};
+
+/* Translation and Protection Tables Parameters */
+
+struct tavorprm_tptparams_st { /* Little Endian */
+ pseudo_bit_t mpt_base_adr_h[0x00020];/* MPT - Memory Protection Table base physical address [63:32].
+ Entry size is 64 bytes.
+ Table must be aligned to its size.
+ Address may be set to zero if address translation and protection is not supported. */
+/* -------------- */
+ pseudo_bit_t mpt_base_adr_l[0x00020];/* MPT - Memory Protection Table base physical address [31:0].
+ Entry size is 64 bytes.
+ Table must be aligned to its size.
+ Address may be set to zero if address translation and protection is not supported. */
+/* -------------- */
+ pseudo_bit_t log_mpt_sz[0x00006]; /* Log (base 2) of the number of region/windows entries in the MPT table. */
+ pseudo_bit_t reserved0[0x00002];
+ pseudo_bit_t pfto[0x00005]; /* Page Fault RNR Timeout -
+ The field returned in RNR Naks generated when a page fault is detected.
+ It has no effect when on-demand-paging is not used. */
+ pseudo_bit_t reserved1[0x00003];
+ pseudo_bit_t mtt_segment_size[0x00003];/* The size of MTT segment is 64*2^MTT_Segment_Size bytes */
+ pseudo_bit_t reserved2[0x0000d];
+/* -------------- */
+ pseudo_bit_t mtt_version[0x00008]; /* Version of MTT page walk. Must be zero */
+ pseudo_bit_t reserved3[0x00018];
+/* -------------- */
+ pseudo_bit_t mtt_base_addr_h[0x00020];/* MTT - Memory Translation table base physical address [63:32].
+ Table must be aligned to its size.
+ Address may be set to zero if address translation and protection is not supported. */
+/* -------------- */
+ pseudo_bit_t mtt_base_addr_l[0x00020];/* MTT - Memory Translation table base physical address [31:0].
+ Table must be aligned to its size.
+ Address may be set to zero if address translation and protection is not supported. */
+/* -------------- */
+ pseudo_bit_t reserved4[0x00040];
+/* -------------- */
+};
+
+/* Multicast Support Parameters */
+
+struct tavorprm_multicastparam_st { /* Little Endian */
+ pseudo_bit_t mc_base_addr_h[0x00020];/* Base Address of the Multicast Table [63:32].
+ The base address must be aligned to the entry size.
+ Address may be set to zero if multicast is not supported. */
+/* -------------- */
+ pseudo_bit_t mc_base_addr_l[0x00020];/* Base Address of the Multicast Table [31:0].
+ The base address must be aligned to the entry size.
+ Address may be set to zero if multicast is not supported. */
+/* -------------- */
+ pseudo_bit_t reserved0[0x00040];
+/* -------------- */
+ pseudo_bit_t log_mc_table_entry_sz[0x00010];/* Log2 of the Size of multicast group member (MGM) entry.
+ Must be greater than 5 (to allow CTRL and GID sections).
+ That implies the number of QPs per MC table entry. */
+ pseudo_bit_t reserved1[0x00010];
+/* -------------- */
+ pseudo_bit_t mc_table_hash_sz[0x00011];/* Number of entries in multicast DGID hash table (must be power of 2)
+ INIT_HCA - the required number of entries
+ QUERY_HCA - the actual number of entries assigned by firmware (will be less than or equal to the amount required in INIT_HCA) */
+ pseudo_bit_t reserved2[0x0000f];
+/* -------------- */
+ pseudo_bit_t log_mc_table_sz[0x00005];/* Log2 of the overall number of MC entries in the MCG table (includes both hash and auxiliary tables) */
+ pseudo_bit_t reserved3[0x00013];
+ pseudo_bit_t mc_hash_fn[0x00003]; /* Multicast hash function
+ 0 - Default hash function
+ other - reserved */
+ pseudo_bit_t reserved4[0x00005];
+/* -------------- */
+ pseudo_bit_t reserved5[0x00020];
+/* -------------- */
+};
+
+/* Memory Access Parameters for UD Address Vector Table */
+
+struct tavorprm_udavtable_memory_parameters_st { /* Little Endian */
+ pseudo_bit_t l_key[0x00020]; /* L_Key used to access TPT */
+/* -------------- */
+ pseudo_bit_t pd[0x00018]; /* PD used by TPT for matching against PD of region entry being accessed. */
+ pseudo_bit_t reserved0[0x00005];
+ pseudo_bit_t xlation_en[0x00001]; /* When cleared, address is physical address and no translation will be done. When set, address is virtual. TPT will be accessed in both cases for address decoding purposes. */
+ pseudo_bit_t reserved1[0x00002];
+/* -------------- */
+};
+
+/* QPC/EEC/CQC/EQC/RDB Parameters */
+
+struct tavorprm_qpcbaseaddr_st { /* Little Endian */
+ pseudo_bit_t reserved0[0x00080];
+/* -------------- */
+ pseudo_bit_t qpc_base_addr_h[0x00020];/* QPC Base Address [63:32]
+ Table must be aligned on its size */
+/* -------------- */
+ pseudo_bit_t log_num_of_qp[0x00005];/* Log base 2 of number of supported QPs */
+ pseudo_bit_t reserved1[0x00002];
+ pseudo_bit_t qpc_base_addr_l[0x00019];/* QPC Base Address [31:7]
+ Table must be aligned on its size */
+/* -------------- */
+ pseudo_bit_t reserved2[0x00040];
+/* -------------- */
+ pseudo_bit_t eec_base_addr_h[0x00020];/* EEC Base Address [63:32]
+ Table must be aligned on its size.
+ Address may be set to zero if RD is not supported. */
+/* -------------- */
+ pseudo_bit_t log_num_of_ee[0x00005];/* Log base 2 of number of supported EEs. */
+ pseudo_bit_t reserved3[0x00002];
+ pseudo_bit_t eec_base_addr_l[0x00019];/* EEC Base Address [31:7]
+ Table must be aligned on its size
+ Address may be set to zero if RD is not supported. */
+/* -------------- */
+ pseudo_bit_t srqc_base_addr_h[0x00020];/* SRQ Context Base Address [63:32]
+ Table must be aligned on its size
+ Address may be set to zero if SRQ is not supported. */
+/* -------------- */
+ pseudo_bit_t log_num_of_srq[0x00005];/* Log base 2 of number of supported SRQs. */
+ pseudo_bit_t srqc_base_addr_l[0x0001b];/* SRQ Context Base Address [31:5]
+ Table must be aligned on its size
+ Address may be set to zero if SRQ is not supported. */
+/* -------------- */
+ pseudo_bit_t cqc_base_addr_h[0x00020];/* CQC Base Address [63:32]
+ Table must be aligned on its size */
+/* -------------- */
+ pseudo_bit_t log_num_of_cq[0x00005];/* Log base 2 of number of supported CQs. */
+ pseudo_bit_t reserved4[0x00001];
+ pseudo_bit_t cqc_base_addr_l[0x0001a];/* CQC Base Address [31:6]
+ Table must be aligned on its size */
+/* -------------- */
+ pseudo_bit_t reserved5[0x00040];
+/* -------------- */
+ pseudo_bit_t eqpc_base_addr_h[0x00020];/* Extended QPC Base Address [63:32]
+ Table has same number of entries as QPC table.
+ Table must be aligned to entry size. */
+/* -------------- */
+ pseudo_bit_t eqpc_base_addr_l[0x00020];/* Extended QPC Base Address [31:0]
+ Table has same number of entries as QPC table.
+ Table must be aligned to entry size. */
+/* -------------- */
+ pseudo_bit_t reserved6[0x00040];
+/* -------------- */
+ pseudo_bit_t eeec_base_addr_h[0x00020];/* Extended EEC Base Address [63:32]
+ Table has same number of entries as EEC table.
+ Table must be aligned to entry size.
+ Address may be set to zero if RD is not supported. */
+/* -------------- */
+ pseudo_bit_t eeec_base_addr_l[0x00020];/* Extended EEC Base Address [31:0]
+ Table has same number of entries as EEC table.
+ Table must be aligned to entry size.
+ Address may be set to zero if RD is not supported. */
+/* -------------- */
+ pseudo_bit_t reserved7[0x00040];
+/* -------------- */
+ pseudo_bit_t eqc_base_addr_h[0x00020];/* EQC Base Address [63:32]
+ Address may be set to zero if EQs are not supported.
+ Table must be aligned to entry size. */
+/* -------------- */
+ pseudo_bit_t log_num_eq[0x00004]; /* Log base 2 of number of supported EQs.
+ Must be 6 or less in InfiniHost. */
+ pseudo_bit_t reserved8[0x00002];
+ pseudo_bit_t eqc_base_addr_l[0x0001a];/* EQC Base Address [31:6]
+ Address may be set to zero if EQs are not supported.
+ Table must be aligned to entry size. */
+/* -------------- */
+ pseudo_bit_t reserved9[0x00040];
+/* -------------- */
+ pseudo_bit_t rdb_base_addr_h[0x00020];/* Base address of table that holds remote read and remote atomic requests [63:32].
+ Table must be aligned to RDB entry size (32 bytes).
+ Address may be set to zero if remote RDMA reads are not supported.
+ Please refer to QP and EE chapter for further explanation on RDB allocation. */
+/* -------------- */
+ pseudo_bit_t rdb_base_addr_l[0x00020];/* Base address of table that holds remote read and remote atomic requests [31:0].
+ Table must be aligned to RDB entry size (32 bytes).
+ This field must always be zero.
+ Please refer to QP and EE chapter for further explanation on RDB allocation. */
+/* -------------- */
+ pseudo_bit_t reserved10[0x00040];
+/* -------------- */
+};
+
+/* Performance Monitors */
+
+struct tavorprm_performance_monitors_st { /* Little Endian */
+ pseudo_bit_t e0[0x00001]; /* Enables counting of respective performance counter */
+ pseudo_bit_t e1[0x00001]; /* Enables counting of respective performance counter */
+ pseudo_bit_t e2[0x00001]; /* Enables counting of respective performance counter */
+ pseudo_bit_t reserved0[0x00001];
+ pseudo_bit_t r0[0x00001]; /* If written to as '1 - resets respective performance counter, if written to az '0 - no change to matter */
+ pseudo_bit_t r1[0x00001]; /* If written to as '1 - resets respective performance counter, if written to az '0 - no change to matter */
+ pseudo_bit_t r2[0x00001]; /* If written to as '1 - resets respective performance counter, if written to az '0 - no change to matter */
+ pseudo_bit_t reserved1[0x00001];
+ pseudo_bit_t i0[0x00001]; /* Interrupt enable on respective counter overflow. '1 - interrupt enabled, '0 - interrupt disabled. */
+ pseudo_bit_t i1[0x00001]; /* Interrupt enable on respective counter overflow. '1 - interrupt enabled, '0 - interrupt disabled. */
+ pseudo_bit_t i2[0x00001]; /* Interrupt enable on respective counter overflow. '1 - interrupt enabled, '0 - interrupt disabled. */
+ pseudo_bit_t reserved2[0x00001];
+ pseudo_bit_t f0[0x00001]; /* Overflow flag. If set, overflow occurred on respective counter. Cleared if written to as '1 */
+ pseudo_bit_t f1[0x00001]; /* Overflow flag. If set, overflow occurred on respective counter. Cleared if written to as '1 */
+ pseudo_bit_t f2[0x00001]; /* Overflow flag. If set, overflow occurred on respective counter. Cleared if written to as '1 */
+ pseudo_bit_t reserved3[0x00001];
+ pseudo_bit_t ev_cnt1[0x00005]; /* Specifies event to be counted by Event_counter1 See XXX for events' definition. */
+ pseudo_bit_t reserved4[0x00003];
+ pseudo_bit_t ev_cnt2[0x00005]; /* Specifies event to be counted by Event_counter2 See XXX for events' definition. */
+ pseudo_bit_t reserved5[0x00003];
+/* -------------- */
+ pseudo_bit_t clock_counter[0x00020];
+/* -------------- */
+ pseudo_bit_t event_counter1[0x00020];
+/* -------------- */
+ pseudo_bit_t event_counter2[0x00020];/* Read/write event counter, counting events specified by EvCntl and EvCnt2 fields repsectively. When the event counter reaches is maximum value of 0xFFFFFF, the next event will cause it to roll over to zero, set F1 or F2 bit respectively and generate interrupt by I1 I2 bit respectively. */
+/* -------------- */
+};
+
+/* QP and EE Context Entry */
+
+struct tavorprm_queue_pair_ee_context_entry_st { /* Little Endian */
+ pseudo_bit_t reserved0[0x00008];
+ pseudo_bit_t de[0x00001]; /* Send/Receive Descriptor Event enable - if set, events can be generated upon descriptors' completion on send/receive queue (controlled by E bit in WQE). Invalid in EE context */
+ pseudo_bit_t reserved1[0x00002];
+ pseudo_bit_t pm_state[0x00002]; /* Path migration state (Migrated, Armed or Rearm)
+ 11-Migrated
+ 00-Armed
+ 01-Rearm
+ 10-Reserved
+ Should be set to 11 for UD QPs and for QPs which do not support APM */
+ pseudo_bit_t reserved2[0x00003];
+ pseudo_bit_t st[0x00003]; /* Service type (invalid in EE context):
+ 000-Reliable Connection
+ 001-Unreliable Connection
+ 010-Reliable Datagram (Not supported for InfiniHost MT23108)
+ 011-Unreliable Datagram
+ 111-MLX transport (raw bits injection). Used for management QPs and RAW */
+ pseudo_bit_t reserved3[0x00009];
+ pseudo_bit_t state[0x00004]; /* QP/EE state:
+ 0 - RST
+ 1 - INIT
+ 2 - RTR
+ 3 - RTS
+ 4 - SQEr
+ 5 - SQD (Send Queue Drained)
+ 6 - ERR
+ 7 - Send Queue Draining
+ 8 - F - RESERVED
+ (Valid for QUERY_QPEE and ERR2RST_QPEE commands only) */
+/* -------------- */
+ pseudo_bit_t sched_queue[0x00004]; /* Schedule queue to be used for WQE scheduling to execution. Determines QOS for this QP. */
+ pseudo_bit_t reserved4[0x0001c];
+/* -------------- */
+ pseudo_bit_t reserved5[0x00018];
+ pseudo_bit_t msg_max[0x00005]; /* Max message size allowed on the QP. Maximum message size is 2^msg_Max.
+ Must be equal to MTU for UD and MLX QPs. */
+ pseudo_bit_t mtu[0x00003]; /* MTU of the QP (Must be the same for both paths: primary and alternative):
+ 0x1 - 256 bytes
+ 0x2 - 512
+ 0x3 - 1024
+ 0x4 - 2048
+ other - reserved
+
+ Should be configured to 0x4 for UD and MLX QPs. */
+/* -------------- */
+ pseudo_bit_t usr_page[0x00018]; /* Index (offset) of user page allocated for this QP (see "non_privileged Access to the HCA Hardware"). Not valid (reserved) in EE context. */
+ pseudo_bit_t reserved6[0x00008];
+/* -------------- */
+ pseudo_bit_t local_qpn_een[0x00018];/* Local QP/EE number Lower bits determine position of this record in QPC table, and - thus - constrained
+ This field is valid for QUERY and ERR2RST commands only. */
+ pseudo_bit_t reserved7[0x00008];
+/* -------------- */
+ pseudo_bit_t remote_qpn_een[0x00018];/* Remote QP/EE number */
+ pseudo_bit_t reserved8[0x00008];
+/* -------------- */
+ pseudo_bit_t reserved9[0x00040];
+/* -------------- */
+ struct tavorprm_address_path_st primary_address_path;/* Primary address path for the QP/EE */
+/* -------------- */
+ struct tavorprm_address_path_st alternative_address_path;/* Alternate address path for the QP/EE */
+/* -------------- */
+ pseudo_bit_t rdd[0x00018]; /* Reliable Datagram Domain */
+ pseudo_bit_t reserved10[0x00008];
+/* -------------- */
+ pseudo_bit_t pd[0x00018]; /* QP protection domain. Not valid (reserved) in EE context. */
+ pseudo_bit_t reserved11[0x00008];
+/* -------------- */
+ pseudo_bit_t wqe_base_adr[0x00020]; /* Bits 63:32 of WQE address for both SQ and RQ.
+ Reserved for EE context. */
+/* -------------- */
+ pseudo_bit_t wqe_lkey[0x00020]; /* memory key (L-Key) to be used to access WQEs. Not valid (reserved) in EE context. */
+/* -------------- */
+ pseudo_bit_t reserved12[0x00003];
+ pseudo_bit_t ssc[0x00001]; /* Send Signaled Completion
+ 1 - all send WQEs generate CQEs.
+ 0 - only send WQEs with C bit set generate completion.
+ Not valid (reserved) in EE context. */
+ pseudo_bit_t sic[0x00001]; /* If set - Ignore end to end credits on send queue. Not valid (reserved) in EE context. */
+ pseudo_bit_t cur_retry_cnt[0x00003];/* Current transport retry counter (QUERY_QPEE only).
+ The current transport retry counter can vary from retry_count down to 1, where 1 means that the last retry attempt is currently executing. */
+ pseudo_bit_t cur_rnr_retry[0x00003];/* Current RNR retry counter (QUERY_QPEE only).
+ The current RNR retry counter can vary from rnr_retry to 1, where 1 means that the last retry attempt is currently executing. */
+ pseudo_bit_t reserved13[0x00002];
+ pseudo_bit_t sae[0x00001]; /* If set - Atomic operations enabled on send queue. Not valid (reserved) in EE context. */
+ pseudo_bit_t swe[0x00001]; /* If set - RDMA - write enabled on send queue. Not valid (reserved) in EE context. */
+ pseudo_bit_t sre[0x00001]; /* If set - RDMA - read enabled on send queue. Not valid (reserved) in EE context. */
+ pseudo_bit_t retry_count[0x00003]; /* Transport timeout Retry count */
+ pseudo_bit_t reserved14[0x00002];
+ pseudo_bit_t sra_max[0x00003]; /* Maximum number of outstanding RDMA-read/Atomic operations allowed in the send queue. Maximum number is 2^SRA_Max. Must be zero in EE context. */
+ pseudo_bit_t flight_lim[0x00004]; /* Number of outstanding (in-flight) messages on the wire allowed for this send queue.
+ Number of outstanding messages is 2^Flight_Lim.
+ Use 0xF for unlimited number of outstanding messages. */
+ pseudo_bit_t ack_req_freq[0x00004]; /* ACK required frequency. ACK required bit will be set in every 2^AckReqFreq packets at least. Not valid for RD QP. */
+/* -------------- */
+ pseudo_bit_t reserved15[0x00020];
+/* -------------- */
+ pseudo_bit_t next_send_psn[0x00018];/* Next PSN to be sent */
+ pseudo_bit_t reserved16[0x00008];
+/* -------------- */
+ pseudo_bit_t cqn_snd[0x00018]; /* CQ number completions from the send queue to be reported to. Not valid (reserved) in EE context. */
+ pseudo_bit_t reserved17[0x00008];
+/* -------------- */
+ pseudo_bit_t next_snd_wqe_0[0x00020];/* Pointer and properties of next WQE on send queue. The format is same as next segment (first 8 bytes) in the WQE. This field is read-only and provided for debug purposes. Not valid (reserved) in EE context. */
+/* -------------- */
+ pseudo_bit_t next_snd_wqe_1[0x00020];/* Pointer and properties of next WQE on send queue. The format is same as next segment (first 8 bytes) in the WQE. This field is read-only and provided for debug purposes. Not valid (reserved) in EE context. */
+/* -------------- */
+ pseudo_bit_t last_acked_psn[0x00018];/* The last acknowledged PSN for the requester (QUERY_QPEE only) */
+ pseudo_bit_t reserved18[0x00008];
+/* -------------- */
+ pseudo_bit_t ssn[0x00018]; /* Requester Send Sequence Number (QUERY_QPEE only) */
+ pseudo_bit_t reserved19[0x00008];
+/* -------------- */
+ pseudo_bit_t reserved20[0x00003];
+ pseudo_bit_t rsc[0x00001]; /* 1 - all receive WQEs generate CQEs.
+ 0 - only receive WQEs with C bit set generate completion.
+ Not valid (reserved) in EE context.
+ */
+ pseudo_bit_t ric[0x00001]; /* Invalid Credits.
+ 1 - place "Invalid Credits" to ACKs sent from this queue.
+ 0 - ACKs report the actual number of end to end credits on the connection.
+ Not valid (reserved) in EE context.
+ Must be set to 1 on QPs which are attached to SRQ. */
+ pseudo_bit_t reserved21[0x00008];
+ pseudo_bit_t rae[0x00001]; /* If set - Atomic operations enabled. on receive queue. Not valid (reserved) in EE context. */
+ pseudo_bit_t rwe[0x00001]; /* If set - RDMA - write enabled on receive queue. Not valid (reserved) in EE context. */
+ pseudo_bit_t rre[0x00001]; /* If set - RDMA - read enabled on receive queue. Not valid (reserved) in EE context. */
+ pseudo_bit_t reserved22[0x00005];
+ pseudo_bit_t rra_max[0x00003]; /* Maximum number of outstanding RDMA-read/Atomic operations allowed on receive queue is 2^RRA_Max.
+ Must be 0 for EE context. */
+ pseudo_bit_t reserved23[0x00008];
+/* -------------- */
+ pseudo_bit_t next_rcv_psn[0x00018]; /* Next (expected) PSN on receive */
+ pseudo_bit_t min_rnr_nak[0x00005]; /* Minimum RNR NAK timer value (TTTTT field encoding according to the IB spec Vol1 9.7.5.2.8).
+ Not valid (reserved) in EE context. */
+ pseudo_bit_t reserved24[0x00003];
+/* -------------- */
+ pseudo_bit_t reserved25[0x00005];
+ pseudo_bit_t ra_buff_indx[0x0001b]; /* Index to outstanding read/atomic buffer.
+ This field constructs the address to the RDB for maintaining the incoming RDMA read and atomic requests. */
+/* -------------- */
+ pseudo_bit_t cqn_rcv[0x00018]; /* CQ number completions from receive queue to be reported to. Not valid (reserved) in EE context. */
+ pseudo_bit_t reserved26[0x00008];
+/* -------------- */
+ pseudo_bit_t next_rcv_wqe_0[0x00020];/* Pointer and properties of next WQE on the receive queue. This format is same as next segment (first 8 bytes) in the WQE.This field is read-only and provided for debug purposes. Not valid (reserved) in EE context. */
+/* -------------- */
+ pseudo_bit_t next_rcv_wqe_1[0x00020];/* Pointer and properties of next WQE on the receive queue. This format is same as next segment (first 8 bytes) in the WQE.This field is read-only and provided for debug purposes. Not valid (reserved) in EE context. */
+/* -------------- */
+ pseudo_bit_t q_key[0x00020]; /* Q_Key to be validated against received datagrams.
+ On send datagrams, if Q_Key[31] specified in the WQE is set, then this Q_Key will be transmitted in the outgoing message.
+ Not valid (reserved) in EE context. */
+/* -------------- */
+ pseudo_bit_t srqn[0x00018]; /* SRQN - Shared Receive Queue Number - specifies the SRQ number from which the QP dequeues receive descriptors.
+ SRQN is valid only if SRQ bit is set. Not valid (reserved) in EE context. */
+ pseudo_bit_t srq[0x00001]; /* SRQ - Shared Receive Queue. If this bit is set, then the QP is associated with a SRQ. Not valid (reserved) in EE context. */
+ pseudo_bit_t reserved27[0x00007];
+/* -------------- */
+ pseudo_bit_t rmsn[0x00018]; /* Responder current message sequence number (QUERY_QPEE only) */
+ pseudo_bit_t reserved28[0x00008];
+/* -------------- */
+ pseudo_bit_t reserved29[0x00260];
+/* -------------- */
+};
+
+/* MOD_STAT_CFG */
+
+struct tavorprm_mod_stat_cfg_st { /* Little Endian */
+ pseudo_bit_t log_max_srqs[0x00005]; /* Log (base 2) of the number of SRQs to allocate (0 if no SRQs are required), valid only if srq bit is set. */
+ pseudo_bit_t reserved0[0x00001];
+ pseudo_bit_t srq[0x00001]; /* When set SRQs are supported */
+ pseudo_bit_t srq_m[0x00001]; /* Modify SRQ parameters */
+ pseudo_bit_t reserved1[0x00018];
+/* -------------- */
+ pseudo_bit_t reserved2[0x007e0];
+/* -------------- */
+};
+
+/* SRQ Context */
+
+struct tavorprm_srq_context_st { /* Little Endian */
+ pseudo_bit_t wqe_addr_h[0x00020]; /* WQE base address for the SRQ [63:32]
+ Must be set at SW2HW_SRQ */
+/* -------------- */
+ pseudo_bit_t ds[0x00006]; /* Descriptor Size on the SRQ in units of 16 bytes */
+ pseudo_bit_t next_wqe_addr_l[0x0001a];/* Next WQE address for the SRQ [31:6]
+ Valid only on QUERY_SRQ and HW2SW_SRQ commands. */
+/* -------------- */
+ pseudo_bit_t pd[0x00018]; /* SRQ PD - used for descriptor fetching on the SRQ and for data scatter on send operations on QPs attached to SRQ.
+ In InfiniHost MT23108 SRQ.PD must be equal to the PD of all QPs which are attached to the SRQ */
+ pseudo_bit_t reserved0[0x00004];
+ pseudo_bit_t state[0x00004]; /* SRQ State:
+ 1111 - SW Ownership
+ 0000 - HW Ownership
+ 0001 - Error
+ Valid only on QUERY_SRQ and HW2SW_SRQ commands. */
+/* -------------- */
+ pseudo_bit_t l_key[0x00020]; /* L_Key for descriptor fetching on the SRQ */
+/* -------------- */
+ pseudo_bit_t uar[0x00018]; /* SRQ User Access Region - Index (offset) of user page allocated for the SRQ (see "Non Privileged Access to the HCA HW"). */
+ pseudo_bit_t reserved1[0x00008];
+/* -------------- */
+ pseudo_bit_t wqe_cnt[0x00010]; /* WQE count on the SRQ.
+ Valid only on QUERY_SRQ and HW2SW_SRQ commands. */
+ pseudo_bit_t lwm[0x00010]; /* Limit Water Mark - if the LWM is not zero, and the wqe_cnt drops below LWM when a WQE is dequeued from the SRQ, then a SRQ limit event is fired and the LWM is set to zero. */
+/* -------------- */
+ pseudo_bit_t reserved2[0x00010];
+ pseudo_bit_t reserved3[0x00010];
+/* -------------- */
+ pseudo_bit_t reserved4[0x00020];
+/* -------------- */
+};
+
+/* InfiniHost Configuration Registers */
+
+struct tavorprm_mt23108_configuration_registers_st { /* Little Endian */
+ pseudo_bit_t reserved0[0x403400];
+/* -------------- */
+ struct tavorprm_hca_command_register_st hca_command_interface_register;/* HCA Command Register */
+/* -------------- */
+ pseudo_bit_t reserved1[0x00320];
+/* -------------- */
+ pseudo_bit_t ecr_h[0x00020]; /* Event Cause Register[63:32]. Each bit in the ECR corresponds to one of the 64 Event Queues in InfiniHost. If bit is set, interrupt was asserted due to event reported on corresponding event queue. This register is read-only; writing to this register will cause undefined results
+ */
+/* -------------- */
+ pseudo_bit_t ecr_l[0x00020]; /* Event Cause Register[31:0]. Each bit in the ECR corresponds to one of the 64 Event Queues in InfiniHost. If bit is set, interrupt was asserted due to event reported on corresponding event queue. This register is read-only; writing to this register will cause undefined results
+ */
+/* -------------- */
+ pseudo_bit_t clr_ecr_h[0x00020]; /* Clear Event Cause Register[63:32].
+ This register is used to clear bits in ECR register. Each set bit in data written to this register clears corresponding bit in the ECR register, Each bit written with zero has no effect. This register is write-only. Reading from this register will cause undefined result
+ */
+/* -------------- */
+ pseudo_bit_t clr_ecr_l[0x00020]; /* Clear Event Cause Register[31:0].
+ This register is used to clear bits in ECR register. Each set bit in data written to this register clears corresponding bit in the ECR register, Each bit written with zero has no effect. This register is write-only. Reading from this register will cause undefined result
+ */
+/* -------------- */
+ pseudo_bit_t reserved2[0x4c780];
+/* -------------- */
+ pseudo_bit_t reserved3[0x01000];
+/* -------------- */
+ pseudo_bit_t reserved4[0x32f6c0];
+/* -------------- */
+ pseudo_bit_t clr_int_h[0x00020]; /* Clear Interrupt [63:32]
+ This register is used to clear (de-assert) interrupt output pins of InfiniHost. The value to be written in this register is obtained by executing QUERY_ADAPTER command on command interface after system boot. This register is write-only. Reading from this register will cause undefined result */
+/* -------------- */
+ pseudo_bit_t clr_int_l[0x00020]; /* Clear Interrupt [31:0]
+ This register is used to clear (de-assert) interrupt output pins of InfiniHost. The value to be written in this register is obtained by executing QUERY_ADAPTER command on command interface after system boot. This register is write-only. Reading from this register will cause undefined result */
+/* -------------- */
+ pseudo_bit_t reserved5[0x7f900];
+/* -------------- */
+};
+
+/* Schedule queues configuration */
+
+struct tavorprm_cfg_schq_st { /* Little Endian */
+ pseudo_bit_t quota[0x00008]; /* Number of WQEs that are executed until preemption of the scheduling queue and switching to the next schedule queue */
+ pseudo_bit_t reserved0[0x00018];
+/* -------------- */
+ pseudo_bit_t rqsq0[0x00008]; /* Weight for requestor schedule queue */
+ pseudo_bit_t rssq0[0x00008]; /* Weight for responder schedule queue */
+ pseudo_bit_t rqsq1[0x00008]; /* Weight for requestor schedule queue */
+ pseudo_bit_t rssq1[0x00008]; /* Weight for responder schedule queue */
+/* -------------- */
+ pseudo_bit_t rqsq2[0x00008]; /* Weight for requestor schedule queue */
+ pseudo_bit_t rssq2[0x00008]; /* Weight for responder schedule queue */
+ pseudo_bit_t rqsq3[0x00008]; /* Weight for requestor schedule queue */
+ pseudo_bit_t rssq3[0x00008]; /* Weight for responder schedule queue */
+/* -------------- */
+ pseudo_bit_t rqsq4[0x00008]; /* Weight for requestor schedule queue */
+ pseudo_bit_t rssq4[0x00008]; /* Weight for responder schedule queue */
+ pseudo_bit_t rqsq5[0x00008]; /* Weight for requestor schedule queue */
+ pseudo_bit_t rssq5[0x00008]; /* Weight for responder schedule queue */
+/* -------------- */
+ pseudo_bit_t rqsq6[0x00008]; /* Weight for requestor schedule queue */
+ pseudo_bit_t rssq6[0x00008]; /* Weight for responder schedule queue */
+ pseudo_bit_t rqsq7[0x00008]; /* Weight for requestor schedule queue */
+ pseudo_bit_t rssq7[0x00008]; /* Weight for responder schedule queue */
+/* -------------- */
+ pseudo_bit_t rqsq8[0x00008]; /* Weight for requestor schedule queue */
+ pseudo_bit_t rssq8[0x00008]; /* Weight for responder schedule queue */
+ pseudo_bit_t rqsq9[0x00008]; /* Weight for requestor schedule queue */
+ pseudo_bit_t rssq9[0x00008]; /* Weight for responder schedule queue */
+/* -------------- */
+ pseudo_bit_t rqsq10[0x00008]; /* Weight for requestor schedule queue */
+ pseudo_bit_t rssq10[0x00008]; /* Weight for responder schedule queue */
+ pseudo_bit_t rqsq11[0x00008]; /* Weight for requestor schedule queue */
+ pseudo_bit_t rssq11[0x00008]; /* Weight for responder schedule queue */
+/* -------------- */
+ pseudo_bit_t rqsq12[0x00008]; /* Weight for requestor schedule queue */
+ pseudo_bit_t rssq12[0x00008]; /* Weight for responder schedule queue */
+ pseudo_bit_t rqsq13[0x00008]; /* Weight for requestor schedule queue */
+ pseudo_bit_t rssq13[0x00008]; /* Weight for responder schedule queue */
+/* -------------- */
+ pseudo_bit_t rqsq14[0x00008]; /* Weight for requestor schedule queue */
+ pseudo_bit_t rssq14[0x00008]; /* Weight for responder schedule queue */
+ pseudo_bit_t rqsq15[0x00008]; /* Weight for requestor schedule queue */
+ pseudo_bit_t rssq15[0x00008]; /* Weight for responder schedule queue */
+/* -------------- */
+ pseudo_bit_t rqsq16[0x00008]; /* Weight for requestor schedule queue */
+ pseudo_bit_t rssq16[0x00008]; /* Weight for responder schedule queue */
+ pseudo_bit_t rqsq17[0x00008]; /* Weight for requestor schedule queue */
+ pseudo_bit_t rssq17[0x00008]; /* Weight for responder schedule queue */
+/* -------------- */
+ pseudo_bit_t rqsq18[0x00008]; /* Weight for requestor schedule queue */
+ pseudo_bit_t rssq18[0x00008]; /* Weight for responder schedule queue */
+ pseudo_bit_t rqsq19[0x00008]; /* Weight for requestor schedule queue */
+ pseudo_bit_t rssq19[0x00008]; /* Weight for responder schedule queue */
+/* -------------- */
+ pseudo_bit_t rqsq20[0x00008]; /* Weight for requestor schedule queue */
+ pseudo_bit_t rssq20[0x00008]; /* Weight for responder schedule queue */
+ pseudo_bit_t rqsq21[0x00008]; /* Weight for requestor schedule queue */
+ pseudo_bit_t rssq21[0x00008]; /* Weight for responder schedule queue */
+/* -------------- */
+ pseudo_bit_t rqsq22[0x00008]; /* Weight for requestor schedule queue */
+ pseudo_bit_t rssq22[0x00008]; /* Weight for responder schedule queue */
+ pseudo_bit_t rqsq23[0x00008]; /* Weight for requestor schedule queue */
+ pseudo_bit_t rssq23[0x00008]; /* Weight for responder schedule queue */
+/* -------------- */
+ pseudo_bit_t rqsq24[0x00008]; /* Weight for requestor schedule queue */
+ pseudo_bit_t rssq24[0x00008]; /* Weight for responder schedule queue */
+ pseudo_bit_t rqsq25[0x00008]; /* Weight for requestor schedule queue */
+ pseudo_bit_t rssq25[0x00008]; /* Weight for responder schedule queue */
+/* -------------- */
+ pseudo_bit_t rqsq26[0x00008]; /* Weight for requestor schedule queue */
+ pseudo_bit_t rssq26[0x00008]; /* Weight for responder schedule queue */
+ pseudo_bit_t rqsq27[0x00008]; /* Weight for requestor schedule queue */
+ pseudo_bit_t rssq27[0x00008]; /* Weight for responder schedule queue */
+/* -------------- */
+ pseudo_bit_t rqsq28[0x00008]; /* Weight for requestor schedule queue */
+ pseudo_bit_t rssq28[0x00008]; /* Weight for responder schedule queue */
+ pseudo_bit_t rqsq29[0x00008]; /* Weight for requestor schedule queue */
+ pseudo_bit_t rssq29[0x00008]; /* Weight for responder schedule queue */
+/* -------------- */
+ pseudo_bit_t rqsq30[0x00008]; /* Weight for requestor schedule queue */
+ pseudo_bit_t rssq30[0x00008]; /* Weight for responder schedule queue */
+ pseudo_bit_t rqsq31[0x00008]; /* Weight for requestor schedule queue */
+ pseudo_bit_t rssq31[0x00008]; /* Weight for responder schedule queue */
+/* -------------- */
+ pseudo_bit_t reserved1[0x005e0];
+/* -------------- */
+};
+
+/* Query BAR */
+
+struct tavorprm_query_bar_st { /* Little Endian */
+ pseudo_bit_t bar_base_h[0x00020]; /* BAR base [63:32] */
+/* -------------- */
+ pseudo_bit_t reserved0[0x00014];
+ pseudo_bit_t bar_base_l[0x0000c]; /* BAR base [31:20] */
+/* -------------- */
+};
+
+/* Performance Counters */
+
+struct tavorprm_performance_counters_st { /* Little Endian */
+ pseudo_bit_t sqpc_access_cnt[0x00020];/* SQPC cache access count */
+/* -------------- */
+ pseudo_bit_t sqpc_miss_cnt[0x00020];/* SQPC cache miss count */
+/* -------------- */
+ pseudo_bit_t reserved0[0x00040];
+/* -------------- */
+ pseudo_bit_t rqpc_access_cnt[0x00020];/* RQPC cache access count */
+/* -------------- */
+ pseudo_bit_t rqpc_miss_cnt[0x00020];/* RQPC cache miss count */
+/* -------------- */
+ pseudo_bit_t reserved1[0x00040];
+/* -------------- */
+ pseudo_bit_t cqc_access_cnt[0x00020];/* CQC cache access count */
+/* -------------- */
+ pseudo_bit_t cqc_miss_cnt[0x00020]; /* CQC cache miss count */
+/* -------------- */
+ pseudo_bit_t reserved2[0x00040];
+/* -------------- */
+ pseudo_bit_t tpt_access_cnt[0x00020];/* TPT cache access count */
+/* -------------- */
+ pseudo_bit_t mpt_miss_cnt[0x00020]; /* MPT cache miss count */
+/* -------------- */
+ pseudo_bit_t mtt_miss_cnt[0x00020]; /* MTT cache miss count */
+/* -------------- */
+ pseudo_bit_t reserved3[0x00620];
+/* -------------- */
+};
+
+/* Transport and CI Error Counters */
+
+struct tavorprm_transport_and_ci_error_counters_st { /* Little Endian */
+ pseudo_bit_t rq_num_lle[0x00020]; /* Responder - number of local length errors.
+ Local Length Errors: Inbound "Send" request message exceeded the responders available buffer space. */
+/* -------------- */
+ pseudo_bit_t sq_num_lle[0x00020]; /* Requester - number of local length errors.
+ Length Errors: RDMA READ response message contained too much or too little payload data. */
+/* -------------- */
+ pseudo_bit_t rq_num_lqpoe[0x00020]; /* Responder - number local QP operation error.
+ 1. Malformed WQE: Responder detected a malformed Receive Queue WQE while processing the packet.
+ 2. Local QP Error: Responder detected a local QP related error while executing the request message. The local error prevented the responder from completing the request. */
+/* -------------- */
+ pseudo_bit_t sq_num_lqpoe[0x00020]; /* Requester - number local QP operation error
+ 1. Local Operation Error: (WQE gather, affiliated or unaffiliated): An error occurred in the requesters local channel interface that either cannot be associated with a certain WQE, or occurred when reading a WQE.
+ */
+/* -------------- */
+ pseudo_bit_t rq_num_leeoe[0x00020]; /* Responder - number local EE operation error.
+ RD */
+/* -------------- */
+ pseudo_bit_t sq_num_leeoe[0x00020]; /* Requester - number local EE operation error.
+ RD */
+/* -------------- */
+ pseudo_bit_t rq_num_lpe[0x00020]; /* Responder - number of local protection errors.
+ Local QP (Protection) Error: Responder detected a local access violation error while executing a send request message. The error prevented the responder from completing the request. */
+/* -------------- */
+ pseudo_bit_t sq_num_lpe[0x00020]; /* Requester - number of local protection errors.
+ Local Memory Protection Error: Requester detected a memory translation/protection (TPT) error.
+ */
+/* -------------- */
+ pseudo_bit_t rq_num_wrfe[0x00020]; /* Responder - number of CQEs with error generated. */
+/* -------------- */
+ pseudo_bit_t sq_num_wrfe[0x00020]; /* Requester - number of CQEs with error generated. */
+/* -------------- */
+ pseudo_bit_t reserved0[0x00020];
+/* -------------- */
+ pseudo_bit_t sq_num_mwbe[0x00020]; /* Requester - number of memory window bind errors. */
+/* -------------- */
+ pseudo_bit_t reserved1[0x00020];
+/* -------------- */
+ pseudo_bit_t sq_num_bre[0x00020]; /* Requester - number of bad response errors.
+ Bad response: Unexpected opcode for the response packet received at the expected response PSN. */
+/* -------------- */
+ pseudo_bit_t rq_num_lae[0x00020]; /* Responder - number of local access errors.
+ Unused. */
+/* -------------- */
+ pseudo_bit_t reserved2[0x00040];
+/* -------------- */
+ pseudo_bit_t sq_num_rire[0x00020]; /* Requester - number of remote invalid request errors.
+ NAK-Invalid Request on:
+ 1. Unsupported OpCode: Responder detected an unsupported OpCode.
+ 2. Unexpected OpCode: Responder detected an error in the sequence of OpCodes, such as a missing "Last" packet.
+ Note: there is no PSN error, thus this does not indicate a dropped packet. */
+/* -------------- */
+ pseudo_bit_t rq_num_rire[0x00020]; /* Responder - number of remote invalid request errors.
+ NAK may or may not be sent.
+ 1. Unsupported or Reserved OpCode: Inbound request OpCode was either reserved, or was for a function not supported by this QP. (E.G. RDMA or ATOMIC on QP not set up for this). For RC this is "QP Async affiliated".
+ 2. Misaligned ATOMIC: VA does not point to an aligned address on an atomic operation.
+ 3. Too many RDMA READ or ATOMIC Requests: There were more requests received and not ACKed than allowed for the connection.
+ 4. Out of Sequence OpCode, current packet is "first" or "Only": The Responder detected an error in the sequence of OpCodes; a missing "Last" packet
+ 5. Out of Sequence OpCode, current packet is not "first" or "Only": The Responder detected an error in the sequence of OpCodes; a missing "First" packet
+ 6. Local Length Error: Inbound "Send" request message exceeded the responder.s available buffer space.
+ 7. Length error: RDMA WRITE request message contained too much or too little payload data compared to the DMA length advertised in the first or only packet.
+ 8. Length error: Payload length was not consistent with the opcode:
+ a: 0 byte <= "only" <= PMTU bytes
+ b: ("first" or "middle") == PMTU bytes
+ c: 1byte <= "last" <= PMTU bytes
+ 9. Length error: Inbound message exceeded the size supported by the CA port. */
+/* -------------- */
+ pseudo_bit_t sq_num_rae[0x00020]; /* Requester - number of remote access errors.
+ NAK-Remote Access Error on:
+ R_Key Violation: Responder detected an invalid R_Key while executing an RDMA Request. */
+/* -------------- */
+ pseudo_bit_t rq_num_rae[0x00020]; /* Responder - number of remote access errors.
+ R_Key Violation Responder detected an R_Key violation while executing an RDMA request.
+ NAK may or may not be sent. */
+/* -------------- */
+ pseudo_bit_t sq_num_roe[0x00020]; /* Requester - number of remote operation errors.
+ NAK-Remote Operation Error on:
+ Remote Operation Error: Responder encountered an error, (local to the responder), which prevented it from completing the request. */
+/* -------------- */
+ pseudo_bit_t rq_num_roe[0x00020]; /* Responder - number of remote operation errors.
+ NAK-Remote Operation Error on:
+ 1. Malformed WQE: Responder detected a malformed Receive Queue WQE while processing the packet.
+ 2. Remote Operation Error: Responder encountered an error, (local to the responder), which prevented it from completing the request. */
+/* -------------- */
+ pseudo_bit_t sq_num_tree[0x00020]; /* Requester - number of transport retries exceeded errors.
+ 1. Packet sequence error: Retry limit exceeded. Responder detected a PSN larger than it expected. The requestor performed retries, and automatic path migration and additional retries, if applicable, but all attempts failed.
+ 2. Implied NAK sequence error: Retry limit exceeded. Requestor detected an ACK with a PSN larger than the expected PSN for an RDMA READ or atomic response. The requestor performed retries, and automatic path migration and additional retries, if applicable, but all attempts failed.
+ 3. Local Ack Timeout error: Retry limit exceeded. No ACK response within timer interval. The requestor performed retries, and automatic path migration and additional retries, but all attempts failed. */
+/* -------------- */
+ pseudo_bit_t reserved3[0x00020];
+/* -------------- */
+ pseudo_bit_t sq_num_rree[0x00020]; /* Requester - number of RNR nak retries exceeded errors.
+ RNR NAK Retry error. Retry limit exceeded. Excessive RNR NAKs returned by the responder: Requestor retried the request "n" times, but received RNR NAK each time. */
+/* -------------- */
+ pseudo_bit_t reserved4[0x00020];
+/* -------------- */
+ pseudo_bit_t sq_num_lrdve[0x00020]; /* Requester - number of local RDD violation errors.
+ RD only. */
+/* -------------- */
+ pseudo_bit_t rq_num_rirdre[0x00020];/* Responder - number of remote invalid RD request errors.
+ RD only. */
+/* -------------- */
+ pseudo_bit_t reserved5[0x00040];
+/* -------------- */
+ pseudo_bit_t sq_num_rabrte[0x00020];/* Requester - number of remote aborted errors.
+ RD only. */
+/* -------------- */
+ pseudo_bit_t reserved6[0x00020];
+/* -------------- */
+ pseudo_bit_t sq_num_ieecne[0x00020];/* Requester - number of invalid EE context number errors.
+ RD only. */
+/* -------------- */
+ pseudo_bit_t reserved7[0x00020];
+/* -------------- */
+ pseudo_bit_t sq_num_ieecse[0x00020];/* Requester - invalid EE context state errors.
+ RD only. */
+/* -------------- */
+ pseudo_bit_t reserved8[0x00380];
+/* -------------- */
+ pseudo_bit_t rq_num_oos[0x00020]; /* Responder - number of out of sequence requests received.
+ Out of Sequence Request Packet: Packet PSN of the inbound request is outside the responders valid PSN window.
+ NAK may or may not be sent. */
+/* -------------- */
+ pseudo_bit_t sq_num_oos[0x00020]; /* Requester - number of out of sequence Naks received.
+ NAK-Sequence Error on:
+ 1. Packet sequence error. Retry limit not exceeded: Responder detected a PSN larger than it expected. Requester may retry the request.
+ 2. Packet sequence error. Retry limit exceeded: Responder detected a PSN larger than it expected. The requestor performed retries, and automatic path migration and additional retries, if applicable, but all attempts failed. */
+/* -------------- */
+ pseudo_bit_t rq_num_mce[0x00020]; /* Responder - number of bad multicast packets received.
+ Missing GID or bad GID. */
+/* -------------- */
+ pseudo_bit_t reserved9[0x00020];
+/* -------------- */
+ pseudo_bit_t rq_num_rsync[0x00020]; /* Responder - number of RESYNC operations.
+ RD only. */
+/* -------------- */
+ pseudo_bit_t sq_num_rsync[0x00020]; /* Requester - number of RESYNC operations.
+ RD only. */
+/* -------------- */
+ pseudo_bit_t rq_num_udsdprd[0x00020];/* The number of UD packets silently discarded on the receive queue due to lack of receive descriptor.
+ Resources Not Ready Error: A UD WQE is not currently available. */
+/* -------------- */
+ pseudo_bit_t reserved10[0x00020];
+/* -------------- */
+ pseudo_bit_t rq_num_ucsdprd[0x00020];/* The number of UC packets silently discarded on the receive queue due to lack of receive descriptor.
+ Resources Not Ready Error: A UC WQE is not currently available. */
+/* -------------- */
+ pseudo_bit_t reserved11[0x003e0];
+/* -------------- */
+ pseudo_bit_t num_cqovf[0x00020]; /* Number of CQ overflows.
+ Incremented each time a completion is discarded due CQ overflow. */
+/* -------------- */
+ pseudo_bit_t num_eqovf[0x00020]; /* Number of EQ overflows.
+ Incremented each time EQ enters the overflow state. */
+/* -------------- */
+ pseudo_bit_t num_baddb[0x00020]; /* Number of bad doorbells.
+ Doorbell dropped due to UAR violation or bad resource state. */
+/* -------------- */
+ pseudo_bit_t reserved12[0x002a0];
+/* -------------- */
+};
+
+/* Event_data Field - HCR Completion Event */
+
+struct tavorprm_hcr_completion_event_st { /* Little Endian */
+ pseudo_bit_t token[0x00010]; /* HCR Token */
+ pseudo_bit_t reserved0[0x00010];
+/* -------------- */
+ pseudo_bit_t reserved1[0x00020];
+/* -------------- */
+ pseudo_bit_t status[0x00008]; /* HCR Status */
+ pseudo_bit_t reserved2[0x00018];
+/* -------------- */
+ pseudo_bit_t out_param_h[0x00020]; /* HCR Output Parameter [63:32] */
+/* -------------- */
+ pseudo_bit_t out_param_l[0x00020]; /* HCR Output Parameter [31:0] */
+/* -------------- */
+ pseudo_bit_t reserved3[0x00020];
+/* -------------- */
+};
+
+/* Completion with Error CQE */
+
+struct tavorprm_completion_with_error_st { /* Little Endian */
+ pseudo_bit_t myqpn[0x00018]; /* Indicates the QP for which completion is being reported */
+ pseudo_bit_t reserved0[0x00008];
+/* -------------- */
+ pseudo_bit_t reserved1[0x00060];
+/* -------------- */
+ pseudo_bit_t db_cnt[0x00010]; /* Doorbell count */
+ pseudo_bit_t reserved2[0x00008];
+ pseudo_bit_t syndrome[0x00008]; /* Completion with error syndrome:
+ 0x01 - Local Length Error
+ 0x02 - Local QP Operation Error
+ 0x03 - Local EE Context Operation Error
+ 0x04 - Local Protection Error
+ 0x05 - Work Request Flushed Error
+ 0x06 - Memory Window Bind Error
+ 0x10 - Bad Response Error
+ 0x11 - Local Access Error
+ 0x12 - Remote Invalid Request Error
+ 0x13 - Remote Access Error
+ 0x14 - Remote Operation Error
+ 0x15 - Transport Retry Counter Exceeded
+ 0x16 - RNR Retry Counter Exceeded
+ 0x20 - Local RDD Violation Error
+ 0x21 - Remote Invalid RD Request
+ 0x22 - Remote Aborted Error
+ 0x23 - Invalid EE Context Number
+ 0x24 - Invalid EE Context State
+ other - Reserved
+ Syndrome is defined according to the IB specification volume 1. For detailed explanation of the syndromes, refer to chapters 10-11 of the IB specification rev 1.1. */
+/* -------------- */
+ pseudo_bit_t reserved3[0x00020];
+/* -------------- */
+ pseudo_bit_t wqe_size[0x00006]; /* Size (in 16-byte chunks) of WQE completion is reported for */
+ pseudo_bit_t wqe_addr[0x0001a]; /* Bits 31:6 of WQE virtual address completion is reported for. The 6 least significant bits are zero. */
+/* -------------- */
+ pseudo_bit_t reserved4[0x00007];
+ pseudo_bit_t owner[0x00001]; /* Owner field. Zero value of this field means SW ownership of CQE. */
+ pseudo_bit_t reserved5[0x00010];
+ pseudo_bit_t opcode[0x00008]; /* The opcode of WQE completion is reported for.
+
+ The following values are reported in case of completion with error:
+ 0xFE - For completion with error on Receive Queues
+ 0xFF - For completion with error on Send Queues */
+/* -------------- */
+};
+
+/* Resize CQ Input Mailbox */
+
+struct tavorprm_resize_cq_st { /* Little Endian */
+ pseudo_bit_t reserved0[0x00020];
+/* -------------- */
+ pseudo_bit_t start_addr_h[0x00020]; /* Start address of CQ[63:32].
+ Must be aligned on CQE size (32 bytes) */
+/* -------------- */
+ pseudo_bit_t start_addr_l[0x00020]; /* Start address of CQ[31:0].
+ Must be aligned on CQE size (32 bytes) */
+/* -------------- */
+ pseudo_bit_t reserved1[0x00018];
+ pseudo_bit_t log_cq_size[0x00005]; /* Log (base 2) of the CQ size (in entries) */
+ pseudo_bit_t reserved2[0x00003];
+/* -------------- */
+ pseudo_bit_t reserved3[0x00060];
+/* -------------- */
+ pseudo_bit_t l_key[0x00020]; /* Memory key (L_Key) to be used to access CQ */
+/* -------------- */
+ pseudo_bit_t reserved4[0x00100];
+/* -------------- */
+};
+
+/* SYS_EN Output Parameter */
+
+struct tavorprm_sys_en_out_param_st { /* Little Endian */
+ pseudo_bit_t reserved0[0x00020];
+/* -------------- */
+ pseudo_bit_t spd[0x00001]; /* 0 - DIMM SPD was read from DIMM
+ 1 - DIMM SPD was read from InfiniHost NVMEM */
+ pseudo_bit_t sladr[0x00003]; /* SPD Slave Address 3 LSBits.
+ Valid only if spd bit is 0. */
+ pseudo_bit_t sock_num[0x00002]; /* DIMM socket number (for double sided DIMM one of the two numbers will be reported) */
+ pseudo_bit_t syn[0x00004]; /* Error Syndrome
+ 0 - reserved
+ 1 - SPD error (e.g. checksum error, no response, error while reading)
+ 2 - DIMM out of bounds (e.g. DIMM rows number is not between 7 and 14, DIMM type is not 2)
+ 3 - DIMM conflict (e.g. mix of registered and unbuffered DIMMs, CAS latency conflict)
+ 4 - Calibration error
+ 5 - reserved
+ 6- DDR Memory check failed
+ other - Error, reserved */
+ pseudo_bit_t reserved1[0x00016];
+/* -------------- */
+};
+
+/* Query Debug Message */
+
+struct tavorprm_query_debug_msg_st { /* Little Endian */
+ pseudo_bit_t base_addr_h[0x00020]; /* Debug Buffers Base Address [63:32] */
+/* -------------- */
+ pseudo_bit_t base_addr_l[0x00020]; /* Debug Buffers Base Address [31:0] */
+/* -------------- */
+ pseudo_bit_t buf_sz[0x00020]; /* Debug Buffer Size (in bytes) */
+/* -------------- */
+ pseudo_bit_t reserved0[0x00020];
+/* -------------- */
+ pseudo_bit_t trc_hdr_sz[0x00020]; /* Trace message header size in dwords. */
+/* -------------- */
+ pseudo_bit_t trc_arg_num[0x00020]; /* The number of arguments per trace message. */
+/* -------------- */
+ pseudo_bit_t reserved1[0x000c0];
+/* -------------- */
+ pseudo_bit_t dbg_msk_h[0x00020]; /* Debug messages mask [63:32] */
+/* -------------- */
+ pseudo_bit_t dbg_msk_l[0x00020]; /* Debug messages mask [31:0] */
+/* -------------- */
+ pseudo_bit_t reserved2[0x00040];
+/* -------------- */
+ pseudo_bit_t fs_base_addr0_h[0x00020];/* Base address for format string for irisc 0 bits[63:32] */
+/* -------------- */
+ pseudo_bit_t fs_base_addr0_l[0x00020];/* Base address for format string for irisc 0 bits[31:0] */
+/* -------------- */
+ pseudo_bit_t fs_base_addr1_h[0x00020];/* Base address for format string for irisc 1 bits[63:32] */
+/* -------------- */
+ pseudo_bit_t fs_base_addr1_l[0x00020];/* Base address for format string for irisc 1 bits[31:0] */
+/* -------------- */
+ pseudo_bit_t fs_base_addr2_h[0x00020];/* Base address for format string for irisc 2 bits[63:32] */
+/* -------------- */
+ pseudo_bit_t fs_base_addr2_l[0x00020];/* Base address for format string for irisc 2 bits[31:0] */
+/* -------------- */
+ pseudo_bit_t fs_base_addr3_h[0x00020];/* Base address for format string for irisc 3 bits[63:32] */
+/* -------------- */
+ pseudo_bit_t fs_base_addr3_l[0x00020];/* Base address for format string for irisc 3 bits[31:0] */
+/* -------------- */
+ pseudo_bit_t fs_base_addr4_h[0x00020];/* Base address for format string for irisc 4 bits[63:32] */
+/* -------------- */
+ pseudo_bit_t fs_base_addr4_l[0x00020];/* Base address for format string for irisc 4 bits[31:0] */
+/* -------------- */
+ pseudo_bit_t fs_base_addr5_h[0x00020];/* Base address for format string for irisc 5 bits[63:32] */
+/* -------------- */
+ pseudo_bit_t fs_base_addr5_l[0x00020];/* Base address for format string for irisc 5 bits[31:0] */
+/* -------------- */
+ pseudo_bit_t reserved3[0x00480];
+/* -------------- */
+};
+
+/* User Access Region */
+
+struct tavorprm_uar_st { /* Little Endian */
+ struct tavorprm_rd_send_doorbell_st rd_send_doorbell;/* Reliable Datagram SQ Doorbell */
+/* -------------- */
+ struct tavorprm_send_doorbell_st send_doorbell;/* SQ Doorbell */
+/* -------------- */
+ struct tavorprm_receive_doorbell_st receive_doorbell;/* RQ Doorbell */
+/* -------------- */
+ struct tavorprm_cq_cmd_doorbell_st cq_command_doorbell;/* CQ Doorbell */
+/* -------------- */
+ struct tavorprm_eq_cmd_doorbell_st eq_command_doorbell;/* EQ Doorbell */
+/* -------------- */
+ pseudo_bit_t reserved0[0x01e80];
+/* -------------- */
+ pseudo_bit_t infini_blast[256][0x00020];/* InfiniBlast buffer (same format as WQE format)
+ Infiniblast is not supported by InfiniHost MT23108 */
+/* -------------- */
+};
+
+/* SET_IB Parameters */
+
+struct tavorprm_set_ib_st { /* Little Endian */
+ pseudo_bit_t rqk[0x00001]; /* Reset QKey Violation Counter */
+ pseudo_bit_t reserved0[0x00011];
+ pseudo_bit_t sig[0x00001]; /* Set System Image GUID to system_image_guid specified.
+ system_image_guid and sig must be the same for all ports. */
+ pseudo_bit_t reserved1[0x0000d];
+/* -------------- */
+ pseudo_bit_t capability_mask[0x00020];/* PortInfo Capability Mask */
+/* -------------- */
+ pseudo_bit_t system_image_guid_h[0x00020];/* System Image GUID[63:32], takes effect only if the SIG bit is set
+ Must be the same for both ports. */
+/* -------------- */
+ pseudo_bit_t system_image_guid_l[0x00020];/* System Image GUID[31:0], takes effect only if the SIG bit is set
+ Must be the same for both ports. */
+/* -------------- */
+ pseudo_bit_t reserved2[0x00180];
+/* -------------- */
+};
+
+/* Multicast Group Member */
+
+struct tavorprm_mgm_entry_st { /* Little Endian */
+ pseudo_bit_t reserved0[0x00006];
+ pseudo_bit_t next_gid_index[0x0001a];/* Index of next Multicast Group Member whose GID maps to same MGID_HASH number.
+ The index is into the Multicast Group Table, which is the comprised the MGHT and AMGM tables.
+ next_gid_index=0 means end of the chain. */
+/* -------------- */
+ pseudo_bit_t reserved1[0x00060];
+/* -------------- */
+ pseudo_bit_t mgid_128_96[0x00020]; /* Multicast group GID[128:96] in big endian format.
+ Use the Reserved GID 0:0:0:0:0:0:0:0 for an invalid entry. */
+/* -------------- */
+ pseudo_bit_t mgid_95_64[0x00020]; /* Multicast group GID[95:64] in big endian format.
+ Use the Reserved GID 0:0:0:0:0:0:0:0 for an invalid entry. */
+/* -------------- */
+ pseudo_bit_t mgid_63_32[0x00020]; /* Multicast group GID[63:32] in big endian format.
+ Use the Reserved GID 0:0:0:0:0:0:0:0 for an invalid entry. */
+/* -------------- */
+ pseudo_bit_t mgid_31_0[0x00020]; /* Multicast group GID[31:0] in big endian format.
+ Use the Reserved GID 0:0:0:0:0:0:0:0 for an invalid entry. */
+/* -------------- */
+ struct tavorprm_mgmqp_st mgmqp_0; /* Multicast Group Member QP */
+/* -------------- */
+ struct tavorprm_mgmqp_st mgmqp_1; /* Multicast Group Member QP */
+/* -------------- */
+ struct tavorprm_mgmqp_st mgmqp_2; /* Multicast Group Member QP */
+/* -------------- */
+ struct tavorprm_mgmqp_st mgmqp_3; /* Multicast Group Member QP */
+/* -------------- */
+ struct tavorprm_mgmqp_st mgmqp_4; /* Multicast Group Member QP */
+/* -------------- */
+ struct tavorprm_mgmqp_st mgmqp_5; /* Multicast Group Member QP */
+/* -------------- */
+ struct tavorprm_mgmqp_st mgmqp_6; /* Multicast Group Member QP */
+/* -------------- */
+ struct tavorprm_mgmqp_st mgmqp_7; /* Multicast Group Member QP */
+/* -------------- */
+};
+
+/* INIT_IB Parameters */
+
+struct tavorprm_init_ib_st { /* Little Endian */
+ pseudo_bit_t reserved0[0x00004];
+ pseudo_bit_t vl_cap[0x00004]; /* Maximum VLs supported on the port, excluding VL15.
+ Legal values are 1,2,4 and 8. */
+ pseudo_bit_t port_width_cap[0x00004];/* IB Port Width
+ 1 - 1x
+ 3 - 1x, 4x
+ 11 - 1x, 4x or 12x (must not be used in InfiniHost MT23108)
+ else - Reserved */
+ pseudo_bit_t mtu_cap[0x00004]; /* Maximum MTU Supported
+ 0x0 - Reserved
+ 0x1 - 256
+ 0x2 - 512
+ 0x3 - 1024
+ 0x4 - 2048
+ 0x5 - 0xF Reserved */
+ pseudo_bit_t g0[0x00001]; /* Set port GUID0 to GUID0 specified */
+ pseudo_bit_t ng[0x00001]; /* Set node GUID to node_guid specified.
+ node_guid and ng must be the same for all ports. */
+ pseudo_bit_t sig[0x00001]; /* Set System Image GUID to system_image_guid specified.
+ system_image_guid and sig must be the same for all ports. */
+ pseudo_bit_t reserved1[0x0000d];
+/* -------------- */
+ pseudo_bit_t max_gid[0x00010]; /* Maximum number of GIDs for the port */
+ pseudo_bit_t reserved2[0x00010];
+/* -------------- */
+ pseudo_bit_t max_pkey[0x00010]; /* Maximum pkeys for the port.
+ Must be the same for both ports. */
+ pseudo_bit_t reserved3[0x00010];
+/* -------------- */
+ pseudo_bit_t reserved4[0x00020];
+/* -------------- */
+ pseudo_bit_t guid0_h[0x00020]; /* EUI-64 GUID assigned by the manufacturer, takes effect only if the G0 bit is set (bits 63:32) */
+/* -------------- */
+ pseudo_bit_t guid0_l[0x00020]; /* EUI-64 GUID assigned by the manufacturer, takes effect only if the G0 bit is set (bits 31:0) */
+/* -------------- */
+ pseudo_bit_t node_guid_h[0x00020]; /* Node GUID[63:32], takes effect only if the NG bit is set
+ Must be the same for both ports. */
+/* -------------- */
+ pseudo_bit_t node_guid_l[0x00020]; /* Node GUID[31:0], takes effect only if the NG bit is set
+ Must be the same for both ports. */
+/* -------------- */
+ pseudo_bit_t system_image_guid_h[0x00020];/* System Image GUID[63:32], takes effect only if the SIG bit is set
+ Must be the same for both ports. */
+/* -------------- */
+ pseudo_bit_t system_image_guid_l[0x00020];/* System Image GUID[31:0], takes effect only if the SIG bit is set
+ Must be the same for both ports. */
+/* -------------- */
+ pseudo_bit_t reserved5[0x006c0];
+/* -------------- */
+};
+
+/* Query Device Limitations */
+
+struct tavorprm_query_dev_lim_st { /* Little Endian */
+ pseudo_bit_t reserved0[0x00080];
+/* -------------- */
+ pseudo_bit_t log_max_qp[0x00005]; /* Log2 of the Maximum number of QPs supported */
+ pseudo_bit_t reserved1[0x00003];
+ pseudo_bit_t log2_rsvd_qps[0x00004];/* Log (base 2) of the number of QPs reserved for firmware use
+ The reserved resources are numbered from 0 to 2^log2_rsvd_qps-1 */
+ pseudo_bit_t reserved2[0x00004];
+ pseudo_bit_t log_max_qp_sz[0x00008];/* The maximum number of WQEs allowed on the RQ or the SQ is 2^log_max_qp_sz-1 */
+ pseudo_bit_t log_max_srq_sz[0x00008];/* The maximum number of WQEs allowed on the SRQ is 2^log_max_srq_sz-1 */
+/* -------------- */
+ pseudo_bit_t log_max_ee[0x00005]; /* Log2 of the Maximum number of EE contexts supported */
+ pseudo_bit_t reserved3[0x00003];
+ pseudo_bit_t log2_rsvd_ees[0x00004];/* Log (base 2) of the number of EECs reserved for firmware use
+ The reserved resources are numbered from 0 to 2^log2_rsvd_ees-1 */
+ pseudo_bit_t reserved4[0x00004];
+ pseudo_bit_t log_max_srqs[0x00005]; /* Log base 2 of the maximum number of SRQs supported, valid only if SRQ bit is set.
+ */
+ pseudo_bit_t reserved5[0x00007];
+ pseudo_bit_t log2_rsvd_srqs[0x00004];/* Log (base 2) of the number of reserved SRQs for firmware use
+ The reserved resources are numbered from 0 to 2^log2_rsvd_srqs-1
+ This parameter is valid only if the SRQ bit is set. */
+/* -------------- */
+ pseudo_bit_t log_max_cq[0x00005]; /* Log2 of the Maximum number of CQs supported */
+ pseudo_bit_t reserved6[0x00003];
+ pseudo_bit_t log2_rsvd_cqs[0x00004];/* Log (base 2) of the number of CQs reserved for firmware use
+ The reserved resources are numbered from 0 to 2^log2_rsrvd_cqs-1 */
+ pseudo_bit_t reserved7[0x00004];
+ pseudo_bit_t log_max_cq_sz[0x00008];/* Log2 of the Maximum CQEs allowed in a CQ */
+ pseudo_bit_t reserved8[0x00008];
+/* -------------- */
+ pseudo_bit_t log_max_eq[0x00003]; /* Log2 of the Maximum number of EQs */
+ pseudo_bit_t reserved9[0x00005];
+ pseudo_bit_t num_rsvd_eqs[0x00004]; /* The number of EQs reserved for firmware use
+ The reserved resources are numbered from 0 to num_rsvd_eqs-1
+ If 0 - no resources are reserved. */
+ pseudo_bit_t reserved10[0x00004];
+ pseudo_bit_t log_max_mpts[0x00006]; /* Log (base 2) of the maximum number of MPT entries (the number of Regions/Windows) */
+ pseudo_bit_t reserved11[0x0000a];
+/* -------------- */
+ pseudo_bit_t log_max_mtt_seg[0x00006];/* Log2 of the Maximum number of MTT segments */
+ pseudo_bit_t reserved12[0x00002];
+ pseudo_bit_t log2_rsvd_mrws[0x00004];/* Log (base 2) of the number of MPTs reserved for firmware use
+ The reserved resources are numbered from 0 to 2^log2_rsvd_mrws-1 */
+ pseudo_bit_t reserved13[0x00004];
+ pseudo_bit_t log_max_mrw_sz[0x00008];/* Log2 of the Maximum Size of Memory Region/Window */
+ pseudo_bit_t reserved14[0x00004];
+ pseudo_bit_t log2_rsvd_mtts[0x00004];/* Log (base 2) of the number of MTT segments reserved for firmware use
+ The reserved resources are numbered from 0 to 2^log2_rsvd_mtts-1
+ */
+/* -------------- */
+ pseudo_bit_t log_max_av[0x00006]; /* Log2 of the Maximum number of Address Vectors */
+ pseudo_bit_t reserved15[0x0001a];
+/* -------------- */
+ pseudo_bit_t log_max_ra_res_qp[0x00006];/* Log2 of the Maximum number of outstanding RDMA read/Atomic per QP as a responder */
+ pseudo_bit_t reserved16[0x0000a];
+ pseudo_bit_t log_max_ra_req_qp[0x00006];/* Log2 of the maximum number of outstanding RDMA read/Atomic per QP as a requester */
+ pseudo_bit_t reserved17[0x0000a];
+/* -------------- */
+ pseudo_bit_t log_max_ra_res_global[0x00006];/* Log2 of the maximum number of RDMA read/atomic operations the HCA responder can support globally. That implies the RDB table size. */
+ pseudo_bit_t reserved18[0x0001a];
+/* -------------- */
+ pseudo_bit_t reserved19[0x00020];
+/* -------------- */
+ pseudo_bit_t num_ports[0x00004]; /* Number of IB ports. */
+ pseudo_bit_t max_vl[0x00004]; /* Maximum VLs supported on each port, excluding VL15 */
+ pseudo_bit_t max_port_width[0x00004];/* IB Port Width
+ 1 - 1x
+ 3 - 1x, 4x
+ 11 - 1x, 4x or 12x
+ else - Reserved */
+ pseudo_bit_t max_mtu[0x00004]; /* Maximum MTU Supported
+ 0x0 - Reserved
+ 0x1 - 256
+ 0x2 - 512
+ 0x3 - 1024
+ 0x4 - 2048
+ 0x5 - 0xF Reserved */
+ pseudo_bit_t local_ca_ack_delay[0x00005];/* The Local CA ACK Delay. This is the value recommended to be returned in Query HCA verb.
+ The delay value in microseconds is computed using 4.096us * 2^(Local_CA_ACK_Delay). */
+ pseudo_bit_t reserved20[0x0000b];
+/* -------------- */
+ pseudo_bit_t log_max_gid[0x00004]; /* Log2 of the maximum number of GIDs per port */
+ pseudo_bit_t reserved21[0x0001c];
+/* -------------- */
+ pseudo_bit_t log_max_pkey[0x00004]; /* Log2 of the max PKey Table Size (per IB port) */
+ pseudo_bit_t reserved22[0x0001c];
+/* -------------- */
+ pseudo_bit_t reserved23[0x00020];
+/* -------------- */
+ pseudo_bit_t rc[0x00001]; /* RC Transport supported */
+ pseudo_bit_t uc[0x00001]; /* UC Transport Supported */
+ pseudo_bit_t ud[0x00001]; /* UD Transport Supported */
+ pseudo_bit_t rd[0x00001]; /* RD Transport Supported
+ RD is not supported in InfiniHost MT23108 */
+ pseudo_bit_t raw_ipv6[0x00001]; /* Raw IPv6 Transport Supported */
+ pseudo_bit_t raw_ether[0x00001]; /* Raw Ethertype Transport Supported */
+ pseudo_bit_t srq[0x00001]; /* SRQ is supported
+ */
+ pseudo_bit_t reserved24[0x00001];
+ pseudo_bit_t pkv[0x00001]; /* PKey Violation Counter Supported */
+ pseudo_bit_t qkv[0x00001]; /* QKey Violation Coutner Supported */
+ pseudo_bit_t reserved25[0x00006];
+ pseudo_bit_t mw[0x00001]; /* Memory windows supported */
+ pseudo_bit_t apm[0x00001]; /* Automatic Path Migration Supported */
+ pseudo_bit_t atm[0x00001]; /* Atomic operations supported (atomicity is guaranteed between QPs on this HCA) */
+ pseudo_bit_t rm[0x00001]; /* Raw Multicast Supported */
+ pseudo_bit_t avp[0x00001]; /* Address Vector Port checking supported */
+ pseudo_bit_t udm[0x00001]; /* UD Multicast Supported */
+ pseudo_bit_t reserved26[0x00002];
+ pseudo_bit_t pg[0x00001]; /* Paging on demand supported */
+ pseudo_bit_t r[0x00001]; /* Router mode supported */
+ pseudo_bit_t reserved27[0x00006];
+/* -------------- */
+ pseudo_bit_t log_pg_sz[0x00008]; /* Minimum system page size supported (log2) .
+ For proper operation it must be less than or equal the hosting platform (CPU) minimum page size. */
+ pseudo_bit_t reserved28[0x00008];
+ pseudo_bit_t uar_sz[0x00006]; /* UAR Area Size = 1MB * 2^uar_sz */
+ pseudo_bit_t reserved29[0x00006];
+ pseudo_bit_t num_rsvd_uars[0x00004];/* The number of UARs reserved for firmware use
+ The reserved resources are numbered from 0 to num_reserved_uars-1
+ Note that UAR 1 is always for the kernel
+ If 0 - no resources are reserved. */
+/* -------------- */
+ pseudo_bit_t reserved30[0x00020];
+/* -------------- */
+ pseudo_bit_t max_desc_sz[0x00010]; /* Max descriptor size in bytes */
+ pseudo_bit_t max_sg[0x00008]; /* The maximum S/G list elements in a WQE (max_desc_sz/16 - 3) */
+ pseudo_bit_t reserved31[0x00008];
+/* -------------- */
+ pseudo_bit_t reserved32[0x00060];
+/* -------------- */
+ pseudo_bit_t log_max_mcg[0x00008]; /* Log2 of the maximum number of multicast groups */
+ pseudo_bit_t num_rsvd_mcgs[0x00004];/* The number of MGMs reserved for firmware use in the MGHT.
+ The reserved resources are numbered from 0 to num_reserved_mcgs-1
+ If 0 - no resources are reserved. */
+ pseudo_bit_t reserved33[0x00004];
+ pseudo_bit_t log_max_qp_mcg[0x00008];/* Log2 of the maximum number of QPs per multicast group */
+ pseudo_bit_t reserved34[0x00008];
+/* -------------- */
+ pseudo_bit_t log_max_rdds[0x00006]; /* Log2 of the maximum number of RDDs */
+ pseudo_bit_t reserved35[0x00006];
+ pseudo_bit_t num_rsvd_rdds[0x00004];/* The number of RDDs reserved for firmware use
+ The reserved resources are numbered from 0 to num_reserved_rdds-1.
+ If 0 - no resources are reserved. */
+ pseudo_bit_t log_max_pd[0x00006]; /* Log2 of the maximum number of PDs */
+ pseudo_bit_t reserved36[0x00006];
+ pseudo_bit_t num_rsvd_pds[0x00004]; /* The number of PDs reserved for firmware use
+ The reserved resources are numbered from 0 to num_reserved_pds-1
+ If 0 - no resources are reserved. */
+/* -------------- */
+ pseudo_bit_t reserved37[0x000c0];
+/* -------------- */
+ pseudo_bit_t qpc_entry_sz[0x00010]; /* QPC Entry Size for the device
+ For the InfiniHost MT23108 entry size is 256 bytes */
+ pseudo_bit_t eec_entry_sz[0x00010]; /* EEC Entry Size for the device
+ For the InfiniHost MT23108 entry size is 256 bytes */
+/* -------------- */
+ pseudo_bit_t eqpc_entry_sz[0x00010];/* Extended QPC entry size for the device
+ For the InfiniHost MT23108 entry size is 32 bytes */
+ pseudo_bit_t eeec_entry_sz[0x00010];/* Extended EEC entry size for the device
+ For the InfiniHost MT23108 entry size is 32 bytes */
+/* -------------- */
+ pseudo_bit_t cqc_entry_sz[0x00010]; /* CQC entry size for the device
+ For the InfiniHost MT23108 entry size is 64 bytes */
+ pseudo_bit_t eqc_entry_sz[0x00010]; /* EQ context entry size for the device
+ For the InfiniHost MT23108 entry size is 64 bytes */
+/* -------------- */
+ pseudo_bit_t uar_scratch_entry_sz[0x00010];/* UAR Scratchpad Entry Size
+ For the InfiniHost MT23108 entry size is 32 bytes */
+ pseudo_bit_t srq_entry_sz[0x00010]; /* SRQ context entry size for the device
+ For the InfiniHost MT23108 entry size is 32 bytes */
+/* -------------- */
+ pseudo_bit_t reserved38[0x00380];
+/* -------------- */
+};
+
+/* QUERY_ADAPTER Parameters Block */
+
+struct tavorprm_query_adapter_st { /* Little Endian */
+ pseudo_bit_t vendor_id[0x00020]; /* Adapter vendor ID */
+/* -------------- */
+ pseudo_bit_t device_id[0x00020]; /* Adapter Device ID */
+/* -------------- */
+ pseudo_bit_t revision_id[0x00020]; /* Adapter Revision ID */
+/* -------------- */
+ pseudo_bit_t reserved0[0x00020];
+/* -------------- */
+ pseudo_bit_t reserved1[0x00018];
+ pseudo_bit_t intapin[0x00008]; /* Interrupt Signal ID of HCA device pin that is connected to the INTA trace in the HCA board.
+ 0..39 and 63 are valid values
+ 255 means INTA trace in board is not connected to the HCA device.
+ All other values are reserved */
+/* -------------- */
+ pseudo_bit_t mode_pci[0x00001]; /* Set when the device is operating in conventional PCI mode (as opposed to PCI-X/PCI-Express). */
+ pseudo_bit_t mode_32bit[0x00001]; /* Set when the device is operating in 32 bit mode (the sampled bus width is 32 bit). */
+ pseudo_bit_t reserved2[0x0001e];
+/* -------------- */
+ pseudo_bit_t reserved3[0x00040];
+/* -------------- */
+ struct tavorprm_vsd_st vsd;
+/* -------------- */
+};
+
+/* QUERY_FW Parameters Block */
+
+struct tavorprm_query_fw_st { /* Little Endian */
+ pseudo_bit_t fw_rev_major[0x00010]; /* Firmware Revision - Major */
+ pseudo_bit_t reserved0[0x00010];
+/* -------------- */
+ pseudo_bit_t fw_rev_minor[0x00010]; /* Firmware Revision - Minor */
+ pseudo_bit_t fw_rev_subminor[0x00010];/* Firmware Sub-minor version (Patch level). */
+/* -------------- */
+ pseudo_bit_t cmd_interface_rev[0x00010];/* Command Interface Interpreter Revision ID */
+ pseudo_bit_t reserved1[0x00010];
+/* -------------- */
+ pseudo_bit_t log_max_outstanding_cmd[0x00008];/* Log2 of the maximum number of commands the HCR can support simultaneously */
+ pseudo_bit_t reserved2[0x00017];
+ pseudo_bit_t dt[0x00001]; /* Debug Trace Support
+ 0 - Debug trace is not supported
+ 1 - Debug trace is supported */
+/* -------------- */
+ pseudo_bit_t cmd_interface_db[0x00001];/* Set if the device accepts commands by means of special doorbells. */
+ pseudo_bit_t reserved3[0x0001f];
+/* -------------- */
+ pseudo_bit_t reserved4[0x00060];
+/* -------------- */
+ pseudo_bit_t fw_base_addr_h[0x00020];/* Physical Address of Firmware Area in DDR Memory [63:32] */
+/* -------------- */
+ pseudo_bit_t fw_base_addr_l[0x00020];/* Physical Address of Firmware Area in DDR Memory [31:0] */
+/* -------------- */
+ pseudo_bit_t fw_end_addr_h[0x00020];/* End of firmware address in DDR memory [63:32] */
+/* -------------- */
+ pseudo_bit_t fw_end_addr_l[0x00020];/* End of firmware address in DDR memory [31:0] */
+/* -------------- */
+ pseudo_bit_t error_buf_start_h[0x00020];/* Read Only buffer for catastrofic error reports. */
+/* -------------- */
+ pseudo_bit_t error_buf_start_l[0x00020];
+/* -------------- */
+ pseudo_bit_t error_buf_size[0x00020];/* Size in words */
+/* -------------- */
+ pseudo_bit_t reserved5[0x000a0];
+/* -------------- */
+ pseudo_bit_t cmd_db_dw1[0x00010]; /* offset in bytes from cmd_db_addr_base where DWord 1 of a Command Interface Doorbell should be written. Valid only if CmdInterfaceDb bit is '1' */
+ pseudo_bit_t cmd_db_dw0[0x00010]; /* offset in bytes from cmd_db_addr_base where DWord 0 of a Command Interface Doorbell should be written. Valid only if CmdInterfaceDb bit is '1' */
+/* -------------- */
+ pseudo_bit_t cmd_db_dw3[0x00010]; /* offset in bytes from cmd_db_addr_base where DWord 3 of a Command Interface Doorbell should be written. Valid only if CmdInterfaceDb bit is '1' */
+ pseudo_bit_t cmd_db_dw2[0x00010]; /* offset in bytes from cmd_db_addr_base where DWord 2 of a Command Interface Doorbell should be written. Valid only if CmdInterfaceDb bit is '1' */
+/* -------------- */
+ pseudo_bit_t cmd_db_dw5[0x00010]; /* offset in bytes from cmd_db_addr_base where DWord 5 of a Command Interface Doorbell should be written. Valid only if CmdInterfaceDb bit is '1' */
+ pseudo_bit_t cmd_db_dw4[0x00010]; /* offset in bytes from cmd_db_addr_base where DWord 4 of a Command Interface Doorbell should be written. Valid only if CmdInterfaceDb bit is '1' */
+/* -------------- */
+ pseudo_bit_t cmd_db_dw7[0x00010]; /* offset in bytes from cmd_db_addr_base where DWord 7 of a Command Interface Doorbell should be written. Valid only if CmdInterfaceDb bit is '1' */
+ pseudo_bit_t cmd_db_dw6[0x00010]; /* offset in bytes from cmd_db_addr_base where DWord 6 of a Command Interface Doorbell should be written. Valid only if CmdInterfaceDb bit is '1' */
+/* -------------- */
+ pseudo_bit_t cmd_db_addr_base_h[0x00020];/* High bits of cmd_db_addr_base, which cmd_db_dw offsets refer to. Valid only if CmdInterfaceDb bit is '1' */
+/* -------------- */
+ pseudo_bit_t cmd_db_addr_base_l[0x00020];/* Low bits of cmd_db_addr_base, which cmd_db_dw offsets refer to. Valid only if CmdInterfaceDb bit is '1' */
+/* -------------- */
+ pseudo_bit_t reserved6[0x004c0];
+/* -------------- */
+};
+
+/* ACCESS_DDR */
+
+struct tavorprm_access_ddr_st { /* Little Endian */
+ struct tavorprm_access_ddr_inject_errors_st access_ddr_inject_errors;
+/* -------------- */
+ pseudo_bit_t reserved0[0x00080];
+/* -------------- */
+};
+
+/* QUERY_DDR Parameters Block */
+
+struct tavorprm_query_ddr_st { /* Little Endian */
+ pseudo_bit_t ddr_start_adr_h[0x00020];/* DDR memory start address [63:32] */
+/* -------------- */
+ pseudo_bit_t ddr_start_adr_l[0x00020];/* DDR memory start address [31:0] */
+/* -------------- */
+ pseudo_bit_t ddr_end_adr_h[0x00020];/* DDR memory end address [63:32] */
+/* -------------- */
+ pseudo_bit_t ddr_end_adr_l[0x00020];/* DDR memory end address [31:0] */
+/* -------------- */
+ pseudo_bit_t di[0x00002]; /* Data Integrity Configuration:
+ 00 - none
+ 01 - Parity
+ 10 - ECC Detection Only
+ 11 - ECC With Correction */
+ pseudo_bit_t ap[0x00002]; /* Auto Precharge Mode
+ 00 - No auto precharge
+ 01 - Auto precharge per transaction
+ 10 - Auto precharge per 64 bytes
+ 11 - reserved */
+ pseudo_bit_t dh[0x00001]; /* When set, DDR is Hidden and can not be accessed from the PCI bus. */
+ pseudo_bit_t reserved0[0x0001b];
+/* -------------- */
+ pseudo_bit_t reserved1[0x00160];
+/* -------------- */
+ struct tavorprm_dimminfo_st dimm0; /* Logical DIMM 0 Parameters */
+/* -------------- */
+ struct tavorprm_dimminfo_st dimm1; /* Logical DIMM 1 Parameters */
+/* -------------- */
+ struct tavorprm_dimminfo_st dimm2; /* Logical DIMM 2 Parameters */
+/* -------------- */
+ struct tavorprm_dimminfo_st dimm3; /* Logical DIMM 3 Parameters */
+/* -------------- */
+ pseudo_bit_t reserved2[0x00200];
+/* -------------- */
+};
+
+/* INIT_HCA & QUERY_HCA Parameters Block */
+
+struct tavorprm_init_hca_st { /* Little Endian */
+ pseudo_bit_t reserved0[0x00060];
+/* -------------- */
+ pseudo_bit_t reserved1[0x00018];
+ pseudo_bit_t hca_core_clock[0x00008];/* Internal Clock Period (in units of 1/16 ns) (QUERY_HCA only) */
+/* -------------- */
+ pseudo_bit_t reserved2[0x00008];
+ pseudo_bit_t router_qp[0x00010]; /* Upper 16 bit to be used as a QP number for router mode. Low order 8 bits are taken from the TClass field of the incoming packet.
+ Valid only if RE bit is set */
+ pseudo_bit_t reserved3[0x00007];
+ pseudo_bit_t re[0x00001]; /* Router Mode Enable
+ If this bit is set, entire packet (including all headers and ICRC) will be considered as a data payload and will be scattered to memory as specified in the descriptor that is posted on the QP matching the TClass field of packet. */
+/* -------------- */
+ pseudo_bit_t udp[0x00001]; /* UD Port Check Enable
+ 0 - Port field in Address Vector is ignored
+ 1 - HCA will check the port field in AV entry (fetched for UD descriptor) against the Port of the UD QP executing the descriptor. */
+ pseudo_bit_t he[0x00001]; /* Host Endianess - Used for Atomic Operations
+ 0 - Host is Little Endian
+ 1 - Host is Big endian
+ */
+ pseudo_bit_t ud[0x00001]; /* Force UD address vector protection check. If this bit is set, Passing address vector as immediate data in WQE is suppressed and privileged memory key will be used by hardware to access UD address vector table. */
+ pseudo_bit_t reserved4[0x00005];
+ pseudo_bit_t responder_exu[0x00004];/* How many execution engines are dedicated to the responder. Legal values are 0x0-0xF. 0 is "auto" */
+ pseudo_bit_t reserved5[0x00004];
+ pseudo_bit_t wqe_quota[0x0000f]; /* Maximum number of WQEs that are executed prior to preemption of execution unit. 0 - reserved. */
+ pseudo_bit_t wqe_quota_en[0x00001]; /* If set - wqe_quota field is used. If cleared - WQE quota is set to "auto" value */
+/* -------------- */
+ pseudo_bit_t reserved6[0x00040];
+/* -------------- */
+ struct tavorprm_qpcbaseaddr_st qpc_eec_cqc_eqc_rdb_parameters;
+/* -------------- */
+ pseudo_bit_t reserved7[0x00080];
+/* -------------- */
+ struct tavorprm_udavtable_memory_parameters_st udavtable_memory_parameters;/* Memory Access Parameters for UD Address Vector Table. Used for QPs/EEc that are configured to use protected Address Vectors. */
+/* -------------- */
+ pseudo_bit_t reserved8[0x00040];
+/* -------------- */
+ struct tavorprm_multicastparam_st multicast_parameters;
+/* -------------- */
+ pseudo_bit_t reserved9[0x00080];
+/* -------------- */
+ struct tavorprm_tptparams_st tpt_parameters;
+/* -------------- */
+ pseudo_bit_t reserved10[0x00080];
+/* -------------- */
+ struct tavorprm_uar_params_st uar_parameters;/* UAR Parameters */
+/* -------------- */
+ pseudo_bit_t reserved11[0x00600];
+/* -------------- */
+};
+
+/* Event Queue Context Table Entry */
+
+struct tavorprm_eqc_st { /* Little Endian */
+ pseudo_bit_t reserved0[0x00008];
+ pseudo_bit_t st[0x00002]; /* Event delivery state machine
+ 01 - Armed
+ 10 - Fired
+ 11 - Always_Armed (auto-rearm)
+ 00 - Reserved */
+ pseudo_bit_t reserved1[0x00007];
+ pseudo_bit_t oi[0x00001]; /* Ignore overrun on this EQ if this bit is set */
+ pseudo_bit_t tr[0x00001]; /* Translation Required. If set - EQ access undergo address translation. */
+ pseudo_bit_t reserved2[0x00005];
+ pseudo_bit_t owner[0x00004]; /* 0 - SW ownership
+ 1 - HW ownership
+ Valid for the QUERY_EQ and HW2SW_EQ commands only */
+ pseudo_bit_t status[0x00004]; /* EQ status:
+ 0000 - OK
+ 1001 - EQ overflow
+ 1010 - EQ write failure
+ Valid for the QUERY_EQ and HW2SW_EQ commands only */
+/* -------------- */
+ pseudo_bit_t start_address_h[0x00020];/* Start Address of Event Queue[63:32].
+ Must be aligned on 32-byte boundary */
+/* -------------- */
+ pseudo_bit_t start_address_l[0x00020];/* Start Address of Event Queue[31:0].
+ Must be aligned on 32-byte boundary */
+/* -------------- */
+ pseudo_bit_t usr_page[0x00018];
+ pseudo_bit_t log_eq_size[0x00005]; /* Amount of entries in this EQ is 2^log_eq_size.
+ Log_eq_size must be bigger than 1 */
+ pseudo_bit_t reserved3[0x00003];
+/* -------------- */
+ pseudo_bit_t pd[0x00018]; /* PD to be used to access EQ */
+ pseudo_bit_t reserved4[0x00008];
+/* -------------- */
+ pseudo_bit_t intr[0x00008]; /* Interrupt (message) to be generated to report event to INT layer.
+ 00iiiiii - specifies GPIO pin to be asserted (according to INTA given in QUERY_ADAPTER)
+ 10jjjjjj - specificies type of interrupt message to be generated (total 64 different messages supported).
+
+ If interrupt generation is not required one of the two following options should be set:
+ 1. ST must be set on creation to Fired state and not EQ arming doorbell should be performed. In this case hardware will not generate any interrupt.
+ 2. intr should be set to 60 decimal
+ */
+ pseudo_bit_t reserved5[0x00018];
+/* -------------- */
+ pseudo_bit_t lost_count[0x00020]; /* Number of events lost due to EQ overrun */
+/* -------------- */
+ pseudo_bit_t lkey[0x00020]; /* Memory key (L-Key) to be used to access EQ */
+/* -------------- */
+ pseudo_bit_t reserved6[0x00040];
+/* -------------- */
+ pseudo_bit_t consumer_indx[0x00020];/* Contains next entry to be read upon polling the event queue.
+ Must be initalized to '0 while opening EQ */
+/* -------------- */
+ pseudo_bit_t producer_indx[0x00020];/* Contains next entry in EQ to be written by the HCA.
+ Must be initalized to '0 while opening EQ. */
+/* -------------- */
+ pseudo_bit_t reserved7[0x00080];
+/* -------------- */
+};
+
+/* Memory Translation Table (MTT) Entry */
+
+struct tavorprm_mtt_st { /* Little Endian */
+ pseudo_bit_t ptag_h[0x00020]; /* High-order bits of physical tag. The size of the field depends on the page size of the region. Maximum PTAG size is 52 bits. */
+/* -------------- */
+ pseudo_bit_t p[0x00001]; /* Present bit. If set, page entry is valid. If cleared, access to this page will generate 'non-present page access fault'. */
+ pseudo_bit_t reserved0[0x0000b];
+ pseudo_bit_t ptag_l[0x00014]; /* Low-order bits of Physical tag. The size of the field depends on the page size of the region. Maximum PTAG size is 52 bits. */
+/* -------------- */
+};
+
+/* Memory Protection Table (MPT) Entry */
+
+struct tavorprm_mpt_st { /* Little Endian */
+ pseudo_bit_t ver[0x00004]; /* Version. Must be zero for InfiniHost */
+ pseudo_bit_t reserved0[0x00004];
+ pseudo_bit_t r_w[0x00001]; /* Defines whether this entry is Region (1) or Window (0) */
+ pseudo_bit_t pa[0x00001]; /* Physical address. If set, no virtual-to-physical address translation will be performed for this region */
+ pseudo_bit_t lr[0x00001]; /* If set - local read access enabled */
+ pseudo_bit_t lw[0x00001]; /* If set - local write access enabled */
+ pseudo_bit_t rr[0x00001]; /* If set - Remote read access enabled. */
+ pseudo_bit_t rw[0x00001]; /* If set - remote write access enabled */
+ pseudo_bit_t a[0x00001]; /* If set - Remote Atomic access is enabled */
+ pseudo_bit_t eb[0x00001]; /* If set - Bind is enabled. Valid for region entry only. */
+ pseudo_bit_t reserved1[0x00001];
+ pseudo_bit_t m_io[0x00001]; /* Memory / I/O
+ 1 - Memory commands used on the uplink bus
+ 0 - I/O commands used on the uplink bus
+ Must be 1 for the InfiniHost MT23108. */
+ pseudo_bit_t reserved2[0x0000a];
+ pseudo_bit_t status[0x00004]; /* Regios/Window Status
+ 0xF - not valid (SW ownership)
+ else - HW ownership
+ Note that an unbound Window is denoted by the reg_wnd_len field equals zero. */
+/* -------------- */
+ pseudo_bit_t page_size[0x00005]; /* Page size used for the region. Actual size is [4K]*2^Page_size bytes.
+ page_size should be less than 20. */
+ pseudo_bit_t reserved3[0x00002];
+ pseudo_bit_t reserved4[0x00001];
+ pseudo_bit_t reserved5[0x00018];
+/* -------------- */
+ pseudo_bit_t mem_key[0x00020]; /* The memory Key. This field is compared to key used to access the region/window. Lower-order bits are restricted (index to the table). */
+/* -------------- */
+ pseudo_bit_t pd[0x00018]; /* Protection Domain */
+ pseudo_bit_t reserved6[0x00001];
+ pseudo_bit_t reserved7[0x00001];
+ pseudo_bit_t reserved8[0x00001];
+ pseudo_bit_t reserved9[0x00001];
+ pseudo_bit_t reserved10[0x00001];
+ pseudo_bit_t reserved11[0x00003];
+/* -------------- */
+ pseudo_bit_t start_address_h[0x00020];/* Start Address[63:32] - Virtual Address where this region/window starts */
+/* -------------- */
+ pseudo_bit_t start_address_l[0x00020];/* Start Address[31:0] - Virtual Address where this region/window starts */
+/* -------------- */
+ pseudo_bit_t reg_wnd_len_h[0x00020];/* Region/Window Length[63:32] */
+/* -------------- */
+ pseudo_bit_t reg_wnd_len_l[0x00020];/* Region/Window Length[31:0] */
+/* -------------- */
+ pseudo_bit_t lkey[0x00020]; /* Must be 0 for SW2HW_MPT.
+ On QUERY_MPT and HW2SW_MPT commands for Memory Window it reflects the LKey of the Region that the Window is bound to. */
+/* -------------- */
+ pseudo_bit_t win_cnt[0x00020]; /* Number of windows bound to this region. Valid for regions only.
+ The field is valid only for the QUERY_MPT and HW2SW_MPT commands. */
+/* -------------- */
+ pseudo_bit_t win_cnt_limit[0x00020];/* The number of windows (limit) that can be bound to this region. If a bind operation is attempted when WIN_CNT == WIN_CNT_LIMIT, the operation will be aborted, a CQE with error will be generated, and the QP will be moved into the error state.
+ Zero means no limit.
+ Note that for best hardware performance, win_cnt_limit should be set to zero. */
+/* -------------- */
+ pseudo_bit_t mtt_seg_adr_h[0x00020];/* Base (first) address of the MTT segment, aligned on segment_size boundary (bits 63:31). */
+/* -------------- */
+ pseudo_bit_t reserved12[0x00006];
+ pseudo_bit_t mtt_seg_adr_l[0x0001a];/* Base (first) address of the MTT segment, aligned on segment_size boundary (bits 31:6). */
+/* -------------- */
+ pseudo_bit_t reserved13[0x00060];
+/* -------------- */
+};
+
+/* Completion Queue Context Table Entry */
+
+struct tavorprm_completion_queue_context_st { /* Little Endian */
+ pseudo_bit_t reserved0[0x00008];
+ pseudo_bit_t st[0x00004]; /* Event delivery state machine
+ 0x0 - DISARMED
+ 0x1 - ARMED (Request for Notification)
+ 0x4 - ARMED SOLICITED (Request Solicited Notification)
+ 0xA - FIRED
+ other - reserved */
+ pseudo_bit_t reserved1[0x00005];
+ pseudo_bit_t oi[0x00001]; /* Ignore overrun of this CQ if this bit is set */
+ pseudo_bit_t tr[0x00001]; /* Translation Required
+ 1 - accesses to CQ will undergo address translation
+ 0 - accesses to CQ will not undergo address translation */
+ pseudo_bit_t reserved2[0x00009];
+ pseudo_bit_t status[0x00004]; /* CQ status
+ 0000 - OK
+ 1001 - CQ overflow
+ 1010 - CQ write failure
+ Valid for the QUERY_CQ and HW2SW_CQ commands only */
+/* -------------- */
+ pseudo_bit_t start_address_h[0x00020];/* Start address of CQ[63:32].
+ Must be aligned on CQE size (32 bytes) */
+/* -------------- */
+ pseudo_bit_t start_address_l[0x00020];/* Start address of CQ[31:0].
+ Must be aligned on CQE size (32 bytes) */
+/* -------------- */
+ pseudo_bit_t usr_page[0x00018]; /* UAR page this CQ can be accessed through (ringinig CQ doorbells) */
+ pseudo_bit_t log_cq_size[0x00005]; /* Log (base 2) of the CQ size (in entries).
+ Maximum CQ size is 128K CQEs (max log_cq_size is 17) */
+ pseudo_bit_t reserved3[0x00003];
+/* -------------- */
+ pseudo_bit_t e_eqn[0x00008]; /* Event Queue this CQ reports errors to (e.g. CQ overflow)
+ Valid values are 0 to 63
+ If configured to value other than 0-63, error events will not be reported on the CQ. */
+ pseudo_bit_t reserved4[0x00018];
+/* -------------- */
+ pseudo_bit_t c_eqn[0x00008]; /* Event Queue this CQ reports completion events to.
+ Valid values are 0 to 63
+ If configured to value other than 0-63, completion events will not be reported on the CQ. */
+ pseudo_bit_t reserved5[0x00018];
+/* -------------- */
+ pseudo_bit_t pd[0x00018]; /* Protection Domain to be used to access CQ.
+ Must be the same PD of the CQ L_Key. */
+ pseudo_bit_t reserved6[0x00008];
+/* -------------- */
+ pseudo_bit_t l_key[0x00020]; /* Memory key (L_Key) to be used to access CQ */
+/* -------------- */
+ pseudo_bit_t last_notified_indx[0x00020];/* Maintained by HW.
+ Valid for QUERY_CQ and HW2SW_CQ commands only. */
+/* -------------- */
+ pseudo_bit_t solicit_producer_indx[0x00020];/* Maintained by HW.
+ Valid for QUERY_CQ and HW2SW_CQ commands only.
+ */
+/* -------------- */
+ pseudo_bit_t consumer_indx[0x00020];/* Contains index to the next entry to be read upon poll for completion. The first completion after passing ownership of CQ from software to hardware will be reported to value passed in this field. Only the low log_cq_size bits may be non-zero. */
+/* -------------- */
+ pseudo_bit_t producer_indx[0x00020];/* Points to the next entry to be written to by Hardware. CQ overrun is reported if Producer_indx + 1 equals to Consumer_indx.
+ Maintained by HW (valid for the QUERY_CQ and HW2SW_CQ commands only) */
+/* -------------- */
+ pseudo_bit_t cqn[0x00018]; /* CQ number. Least significant bits are constrained by the position of this CQ in CQC table
+ Valid for the QUERY_CQ and HW2SW_CQ commands only */
+ pseudo_bit_t reserved7[0x00008];
+/* -------------- */
+ pseudo_bit_t reserved8[0x00060];
+/* -------------- */
+};
+
+/* UD Address Vector */
+
+struct tavorprm_ud_address_vector_st { /* Little Endian */
+ pseudo_bit_t pd[0x00018]; /* Protection Domain */
+ pseudo_bit_t port_number[0x00002]; /* Port number
+ 1 - Port 1
+ 2 - Port 2
+ other - reserved */
+ pseudo_bit_t reserved0[0x00006];
+/* -------------- */
+ pseudo_bit_t rlid[0x00010]; /* Remote (Destination) LID */
+ pseudo_bit_t my_lid_path_bits[0x00007];/* Source LID - the lower 7 bits (upper bits are taken from PortInfo) */
+ pseudo_bit_t g[0x00001]; /* Global address enable - if set, GRH will be formed for packet header */
+ pseudo_bit_t reserved1[0x00008];
+/* -------------- */
+ pseudo_bit_t hop_limit[0x00008]; /* IPv6 hop limit */
+ pseudo_bit_t max_stat_rate[0x00003];/* Maximum static rate control.
+ 0 - 4X injection rate
+ 1 - 1X injection rate
+ other - reserved
+ */
+ pseudo_bit_t reserved2[0x00001];
+ pseudo_bit_t msg[0x00002]; /* Max Message size, size is 256*2^MSG bytes */
+ pseudo_bit_t reserved3[0x00002];
+ pseudo_bit_t mgid_index[0x00006]; /* Index to port GID table
+ mgid_index = (port_number-1) * 2^log_max_gid + gid_index
+ Where:
+ 1. log_max_gid is taken from QUERY_DEV_LIM command
+ 2. gid_index is the index to the GID table */
+ pseudo_bit_t reserved4[0x0000a];
+/* -------------- */
+ pseudo_bit_t flow_label[0x00014]; /* IPv6 flow label */
+ pseudo_bit_t tclass[0x00008]; /* IPv6 TClass */
+ pseudo_bit_t sl[0x00004]; /* InfiniBand Service Level (SL) */
+/* -------------- */
+ pseudo_bit_t rgid_127_96[0x00020]; /* Remote GID[127:96] */
+/* -------------- */
+ pseudo_bit_t rgid_95_64[0x00020]; /* Remote GID[95:64] */
+/* -------------- */
+ pseudo_bit_t rgid_63_32[0x00020]; /* Remote GID[63:32] */
+/* -------------- */
+ pseudo_bit_t rgid_31_0[0x00020]; /* Remote GID[31:0] */
+/* -------------- */
+};
+
+/* GPIO_event_data */
+
+struct tavorprm_gpio_event_data_st { /* Little Endian */
+ pseudo_bit_t reserved0[0x00060];
+/* -------------- */
+ pseudo_bit_t gpio_event_hi[0x00020];/* If any bit is set to 1, then a rising/falling event has occurred on the corrsponding GPIO pin. */
+/* -------------- */
+ pseudo_bit_t gpio_event_lo[0x00020];/* If any bit is set to 1, then a rising/falling event has occurred on the corrsponding GPIO pin. */
+/* -------------- */
+ pseudo_bit_t reserved1[0x00020];
+/* -------------- */
+};
+
+/* Event_data Field - QP/EE Events */
+
+struct tavorprm_qp_ee_event_st { /* Little Endian */
+ pseudo_bit_t qpn_een[0x00018]; /* QP/EE/SRQ number event is reported for */
+ pseudo_bit_t reserved0[0x00008];
+/* -------------- */
+ pseudo_bit_t reserved1[0x00020];
+/* -------------- */
+ pseudo_bit_t reserved2[0x0001c];
+ pseudo_bit_t e_q[0x00001]; /* If set - EEN if cleared - QP in the QPN/EEN field
+ Not valid on SRQ events */
+ pseudo_bit_t reserved3[0x00003];
+/* -------------- */
+ pseudo_bit_t reserved4[0x00060];
+/* -------------- */
+};
+
+/* InfiniHost Type0 Configuration Header */
+
+struct tavorprm_mt23108_type0_st { /* Little Endian */
+ pseudo_bit_t vendor_id[0x00010]; /* Hardwired to 0x15B3 */
+ pseudo_bit_t device_id[0x00010]; /* hardwired to 23108 */
+/* -------------- */
+ pseudo_bit_t command[0x00010]; /* PCI Command Register */
+ pseudo_bit_t status[0x00010]; /* PCI Status Register */
+/* -------------- */
+ pseudo_bit_t revision_id[0x00008];
+ pseudo_bit_t class_code_hca_class_code[0x00018];
+/* -------------- */
+ pseudo_bit_t cache_line_size[0x00008];/* Cache Line Size */
+ pseudo_bit_t latency_timer[0x00008];
+ pseudo_bit_t header_type[0x00008]; /* hardwired to zero */
+ pseudo_bit_t bist[0x00008];
+/* -------------- */
+ pseudo_bit_t bar0_ctrl[0x00004]; /* hard-wired to '0100 */
+ pseudo_bit_t reserved0[0x00010];
+ pseudo_bit_t bar0_l[0x0000c]; /* Lower bits of BAR0 (configuration space) */
+/* -------------- */
+ pseudo_bit_t bar0_h[0x00020]; /* Upper 32 bits of BAR0 (configuration space) */
+/* -------------- */
+ pseudo_bit_t bar1_ctrl[0x00004]; /* Hardwired to '1100 */
+ pseudo_bit_t reserved1[0x00010];
+ pseudo_bit_t bar1_l[0x0000c]; /* Lower bits of BAR1 */
+/* -------------- */
+ pseudo_bit_t bar1_h[0x00020]; /* upper 32 bits of BAR1 (User Access Revion - UAR - space) */
+/* -------------- */
+ pseudo_bit_t bar2_ctrl[0x00004]; /* Hardwired to '1100 */
+ pseudo_bit_t reserved2[0x00010];
+ pseudo_bit_t bar2_l[0x0000c]; /* Lower bits of BAR2 */
+/* -------------- */
+ pseudo_bit_t bar2_h[0x00020]; /* Upper 32 bits of BAR2 - DDR (attached memory) BAR */
+/* -------------- */
+ pseudo_bit_t cardbus_cis_pointer[0x00020];
+/* -------------- */
+ pseudo_bit_t subsystem_vendor_id[0x00010];/* Specified by the device NVMEM configuration */
+ pseudo_bit_t subsystem_id[0x00010]; /* Specified by the device NVMEM configuration */
+/* -------------- */
+ pseudo_bit_t expansion_rom_enable[0x00001];/* Expansion ROM Enable. Hardwired to 0 if expansion ROM is disabled in the device NVMEM configuration. */
+ pseudo_bit_t reserved3[0x0000a];
+ pseudo_bit_t expansion_rom_base_address[0x00015];/* Expansion ROM Base Address (upper 21 bit). Hardwired to 0 if expansion ROM is disabled in the device NVMEM configuration. */
+/* -------------- */
+ pseudo_bit_t capabilities_pointer[0x00008];/* Specified by the device NVMEM configuration */
+ pseudo_bit_t reserved4[0x00018];
+/* -------------- */
+ pseudo_bit_t reserved5[0x00020];
+/* -------------- */
+ pseudo_bit_t interrupt_line[0x00008];
+ pseudo_bit_t interrupt_pin[0x00008];
+ pseudo_bit_t min_gnt[0x00008];
+ pseudo_bit_t max_latency[0x00008];
+/* -------------- */
+ pseudo_bit_t reserved6[0x00100];
+/* -------------- */
+ pseudo_bit_t msi_cap_id[0x00008];
+ pseudo_bit_t msi_next_cap_ptr[0x00008];
+ pseudo_bit_t msi_en[0x00001];
+ pseudo_bit_t multiple_msg_cap[0x00003];
+ pseudo_bit_t multiple_msg_en[0x00003];
+ pseudo_bit_t cap_64_bit_addr[0x00001];
+ pseudo_bit_t reserved7[0x00008];
+/* -------------- */
+ pseudo_bit_t msg_addr_l[0x00020];
+/* -------------- */
+ pseudo_bit_t msg_addr_h[0x00020];
+/* -------------- */
+ pseudo_bit_t msg_data[0x00010];
+ pseudo_bit_t reserved8[0x00010];
+/* -------------- */
+ pseudo_bit_t pcix_cap_id[0x00008];
+ pseudo_bit_t pcix_next_cap_ptr[0x00008];
+ pseudo_bit_t pcix_command_reg[0x00010];/* PCIX command register */
+/* -------------- */
+ pseudo_bit_t pcix_status_reg[0x00020];/* PCIX Status Register */
+/* -------------- */
+ pseudo_bit_t reserved9[0x00440];
+/* -------------- */
+};
+
+/* NTU QP Map Table Entry */
+
+struct tavorprm_ntu_qpm_st { /* Little Endian */
+ pseudo_bit_t va_h[0x00020]; /* Bits 63:32 of the virtual address to be used in IB request, Number of bits to be actually used depends on the page size (eg. will use all 52 for 4K page, 51 for 8K page etc). */
+/* -------------- */
+ pseudo_bit_t wm[0x00002]; /* Amount of data to fill in to the read response buffer prior to delivering read response to uplink
+ 00 - forward
+ 01 - MTU
+ 10 - full message
+ 11 - Reserved */
+ pseudo_bit_t mtu[0x00002]; /* MTUI of the channel to be used by this page, value is 256*2MU bytes */
+ pseudo_bit_t rd_len[0x00003]; /* Length of speculative prefetch for read, value is 16*2RD_Len bytes */
+ pseudo_bit_t fence[0x00002];
+ pseudo_bit_t reserved0[0x00002];
+ pseudo_bit_t err_fence[0x00001]; /* 0,00 - No action in NTU - normal flow
+ 0,01 - Reserved (fence bits value of "01" is not defined)
+ 0,10 - Enter PCU transaction to Error fifo, NO fence trap to consequent transaction
+ 0,11 - Enter PCU transaction to Error fifo, fence trap to consequent transactions
+ 1,xx - Enter PCU transaction to Error fifo, mark QRM indication in error fifo. */
+ pseudo_bit_t va_l[0x00014]; /* Bits 31:12 of the virtual address to be used in IB request, Number of bits to be actually used depends on the page size (eg. will use all 52 for 4K page, 51 for 8K page etc). */
+/* -------------- */
+ pseudo_bit_t rkey[0x00020]; /* RKey to be places for RDMA IB requests message */
+/* -------------- */
+ pseudo_bit_t my_qpn[0x00018]; /* Local QO this page is mapped to */
+ pseudo_bit_t s[0x00001]; /* Force solicit event bit in the descriptor */
+ pseudo_bit_t e[0x00001]; /* Force E-bit in the descriptor */
+ pseudo_bit_t s_r[0x00001]; /* S/R# - generate Send as a result of write hit to this page */
+ pseudo_bit_t b[0x00001]; /* Breakpoint - ptransfer control to firmware for every cycle that hits this page */
+ pseudo_bit_t reserved1[0x00002];
+ pseudo_bit_t ce[0x00001]; /* Cache Enable - entry can be cached if this bit is set. */
+ pseudo_bit_t v[0x00001]; /* Valid bit - the entry is valid only if this bit is set */
+/* -------------- */
+};
+
+/* Event Data Field - Performance Monitor */
+
+struct tavorprm_performance_monitor_event_st { /* Little Endian */
+ struct tavorprm_performance_monitors_st performance_monitor_snapshot;/* Performance monitor snapshot */
+/* -------------- */
+ pseudo_bit_t monitor_number[0x00008];/* 0x01 - SQPC
+ 0x02 - RQPC
+ 0x03 - CQC
+ 0x04 - Rkey
+ 0x05 - TLB
+ 0x06 - port0
+ 0x07 - port1 */
+ pseudo_bit_t reserved0[0x00018];
+/* -------------- */
+ pseudo_bit_t reserved1[0x00040];
+/* -------------- */
+};
+
+/* Event_data Field - Page Faults */
+
+struct tavorprm_page_fault_event_data_st { /* Little Endian */
+ pseudo_bit_t reserved0[0x00040];
+/* -------------- */
+ pseudo_bit_t s_r[0x00001]; /* Send (1) or Receive (0) queue caused page fault */
+ pseudo_bit_t r_l[0x00001]; /* Remote (1) or local (0) access caused fault */
+ pseudo_bit_t w_d[0x00001]; /* WQE (1) or data (0) access caused fault */
+ pseudo_bit_t wqv[0x00001]; /* Indicates whether message caused fault consumes descriptor (valid for receive queue only). */
+ pseudo_bit_t fault_type[0x00004]; /* 0000-0111 - RESERVED
+ 1000 - Translation page not present
+ 1001 - RESERVED
+ 1010 - Page write access violation
+ 1011 - 1101 - RESERVED
+ 1110 - Unsupported non-present page fault
+ 1111 - unsupported write access fault */
+ pseudo_bit_t reserved1[0x00018];
+/* -------------- */
+ pseudo_bit_t va_h[0x00020]; /* Virtual address that caused access fault[63:32] */
+/* -------------- */
+ pseudo_bit_t va_l[0x00020]; /* Virtual address that caused access fault[31:0] */
+/* -------------- */
+ pseudo_bit_t mem_key[0x00020]; /* Memory Key used for address translation */
+/* -------------- */
+};
+
+/* Event_data Field - Port State Change */
+
+struct tavorprm_port_state_change_st { /* Little Endian */
+ pseudo_bit_t reserved0[0x00040];
+/* -------------- */
+ pseudo_bit_t reserved1[0x0001c];
+ pseudo_bit_t p[0x00002]; /* Port number (1 or 2) */
+ pseudo_bit_t reserved2[0x00002];
+/* -------------- */
+ pseudo_bit_t reserved3[0x00060];
+/* -------------- */
+};
+
+/* Event_data Field - Completion Queue Error */
+
+struct tavorprm_completion_queue_error_st { /* Little Endian */
+ pseudo_bit_t cqn[0x00018]; /* CQ number event is reported for */
+ pseudo_bit_t reserved0[0x00008];
+/* -------------- */
+ pseudo_bit_t reserved1[0x00020];
+/* -------------- */
+ pseudo_bit_t syndrome[0x00008]; /* Error syndrome
+ 0x01 - CQ overrun
+ 0x02 - CQ access violation error */
+ pseudo_bit_t reserved2[0x00018];
+/* -------------- */
+ pseudo_bit_t reserved3[0x00060];
+/* -------------- */
+};
+
+/* Event_data Field - Completion Event */
+
+struct tavorprm_completion_event_st { /* Little Endian */
+ pseudo_bit_t cqn[0x00018]; /* CQ number event is reported for */
+ pseudo_bit_t reserved0[0x00008];
+/* -------------- */
+ pseudo_bit_t reserved1[0x000a0];
+/* -------------- */
+};
+
+/* Event Queue Entry */
+
+struct tavorprm_event_queue_entry_st { /* Little Endian */
+ pseudo_bit_t event_sub_type[0x00008];/* Event Sub Type.
+ Defined for events which have sub types, zero elsewhere. */
+ pseudo_bit_t reserved0[0x00008];
+ pseudo_bit_t event_type[0x00008]; /* Event Type */
+ pseudo_bit_t reserved1[0x00008];
+/* -------------- */
+ pseudo_bit_t event_data[6][0x00020];/* Delivers auxilary data to handle event. */
+/* -------------- */
+ pseudo_bit_t reserved2[0x00007];
+ pseudo_bit_t owner[0x00001]; /* Owner of the entry
+ 0 SW
+ 1 HW */
+ pseudo_bit_t reserved3[0x00018];
+/* -------------- */
+};
+
+/* QP/EE State Transitions Command Parameters */
+
+struct tavorprm_qp_ee_state_transitions_st { /* Little Endian */
+ pseudo_bit_t opt_param_mask[0x00020];/* This field defines which optional parameters are passed. Each bit specifies whether optional parameter is passed (set) or not (cleared). The optparammask is defined for each QP/EE command. */
+/* -------------- */
+ pseudo_bit_t reserved0[0x00020];
+/* -------------- */
+ struct tavorprm_queue_pair_ee_context_entry_st qpc_eec_data;/* QPC/EEC data */
+/* -------------- */
+ pseudo_bit_t reserved1[0x007c0];
+/* -------------- */
+};
+
+/* Completion Queue Entry Format */
+
+struct tavorprm_completion_queue_entry_st { /* Little Endian */
+ pseudo_bit_t my_qpn[0x00018]; /* Indicates the QP for which completion is being reported */
+ pseudo_bit_t reserved0[0x00004];
+ pseudo_bit_t ver[0x00004]; /* CQE version.
+ 0 for InfiniHost */
+/* -------------- */
+ pseudo_bit_t my_ee[0x00018]; /* EE context (for RD only).
+ Invalid for Bind and Nop operation on RD. */
+ pseudo_bit_t reserved1[0x00008];
+/* -------------- */
+ pseudo_bit_t rqpn[0x00018]; /* Remote (source) QP number. Valid in Responder CQE only for Datagram QP. */
+ pseudo_bit_t reserved2[0x00008];
+/* -------------- */
+ pseudo_bit_t rlid[0x00010]; /* Remote (source) LID of the message. Valid in Responder of UD QP CQE only. */
+ pseudo_bit_t ml_path[0x00007]; /* My (destination) LID path bits - these are the lowemost LMC bits of the DLID in an incoming UD packet, higher bits of this field, that are not part of the LMC bits are zeroed by HW.
+ Valid in responder of UD QP CQE only.
+ Invalid if incoming message DLID is the permissive LID or incoming message is multicast. */
+ pseudo_bit_t g[0x00001]; /* GRH present indicator. Valid in Responder of UD QP CQE only. */
+ pseudo_bit_t reserved3[0x00001];
+ pseudo_bit_t reserved4[0x00003];
+ pseudo_bit_t sl[0x00004]; /* Service Level of the message. Valid in Responder of UD QP CQE only. */
+/* -------------- */
+ pseudo_bit_t immediate_ethertype_pkey_indx_eecredits[0x00020];/* Valid for receive queue completion only.
+ If Opcode field indicates that this was send/write with immediate, this field contains immediate field of the packet.
+ If completion corresponds to RAW receive queue, bits 15:0 contain Ethertype field of the packet.
+ If completion corresponds to GSI receive queue, bits 31:16 contain index in PKey table that matches PKey of the message arrived.
+ For CQE of send queue of the reliable connection service, bits [4:0] of this field contain the encoded EEcredits received in last ACK of the message.
+ */
+/* -------------- */
+ pseudo_bit_t byte_cnt[0x00020]; /* Byte count of data actually transferred (valid for receive queue completions only) */
+/* -------------- */
+ pseudo_bit_t wqe_size[0x00006]; /* Size (in 16-byte chunks) of WQE completion is reported for */
+ pseudo_bit_t wqe_adr[0x0001a]; /* Bits 31:6 of WQE virtual address completion is reported for. The 6 least significant bits are zero. */
+/* -------------- */
+ pseudo_bit_t reserved5[0x00007];
+ pseudo_bit_t owner[0x00001]; /* Owner field. Zero value of this field means SW ownership of CQE. */
+ pseudo_bit_t reserved6[0x0000d];
+ pseudo_bit_t reserved7[0x00001];
+ pseudo_bit_t reserved8[0x00001];
+ pseudo_bit_t s[0x00001]; /* If set, completion is reported for Send queue, if cleared - receive queue. */
+ pseudo_bit_t opcode[0x00008]; /* The opcode of WQE completion is reported for.
+ For CQEs corresponding to send completion, NOPCODE field of the WQE is copied to this field.
+ For CQEs corresponding to receive completions, opcode field of last packet in the message copied to this field.
+ For CQEs corresponding to the receive queue of QPs mapped to QP1, the opcode will be SEND with Immediate (messages are guaranteed to be SEND only)
+
+ The following values are reported in case of completion with error:
+ 0xFE - For completion with error on Receive Queues
+ 0xFF - For completion with error on Send Queues */
+/* -------------- */
+};
+
+/* */
+
+struct tavorprm_ecc_detect_event_data_st { /* Little Endian */
+ pseudo_bit_t reserved0[0x00080];
+/* -------------- */
+ pseudo_bit_t cause_lsb[0x00001];
+ pseudo_bit_t reserved1[0x00002];
+ pseudo_bit_t cause_msb[0x00001];
+ pseudo_bit_t reserved2[0x00002];
+ pseudo_bit_t err_rmw[0x00001];
+ pseudo_bit_t err_src_id[0x00003];
+ pseudo_bit_t err_da[0x00002];
+ pseudo_bit_t err_ba[0x00002];
+ pseudo_bit_t reserved3[0x00011];
+ pseudo_bit_t overflow[0x00001];
+/* -------------- */
+ pseudo_bit_t err_ra[0x00010];
+ pseudo_bit_t err_ca[0x00010];
+/* -------------- */
+};
+
+/* MAD_IFC Input Mailbox */
+
+struct tavorprm_mad_ifc_st { /* Little Endian */
+ pseudo_bit_t request_mad_packet[64][0x00020];/* Request MAD Packet (256bytes) */
+/* -------------- */
+ pseudo_bit_t my_qpn[0x00018]; /* Destination QP number from the received MAD.
+ This field is reserved if Mad_extended_info indication in the input modifier is clear. */
+ pseudo_bit_t reserved0[0x00008];
+/* -------------- */
+ pseudo_bit_t rqpn[0x00018]; /* Remote (source) QP number from the received MAD.
+ This field is reserved if Mad_extended_info indication in the input modifier is clear. */
+ pseudo_bit_t reserved1[0x00008];
+/* -------------- */
+ pseudo_bit_t rlid[0x00010]; /* Remote (source) LID from the received MAD.
+ This field is reserved if Mad_extended_info indication in the input modifier is clear. */
+ pseudo_bit_t ml_path[0x00007]; /* My (destination) LID path bits from the received MAD.
+ This field is reserved if Mad_extended_info indication in the input modifier is clear. */
+ pseudo_bit_t g[0x00001]; /* If set, the GRH field in valid.
+ This field is reserved if Mad_extended_info indication in the input modifier is clear. */
+ pseudo_bit_t reserved2[0x00004];
+ pseudo_bit_t sl[0x00004]; /* Service Level of the received MAD.
+ This field is reserved if Mad_extended_info indication in the input modifier is clear. */
+/* -------------- */
+ pseudo_bit_t pkey_indx[0x00010]; /* Index in PKey table that matches PKey of the received MAD.
+ This field is reserved if Mad_extended_info indication in the input modifier is clear. */
+ pseudo_bit_t reserved3[0x00010];
+/* -------------- */
+ pseudo_bit_t reserved4[0x00180];
+/* -------------- */
+ pseudo_bit_t grh[10][0x00020]; /* The GRH field of the MAD packet that was scattered to the first 40 bytes pointed to by the scatter list.
+ Valid if Mad_extended_info bit (in the input modifier) and g bit are set.
+ Otherwise this field is reserved. */
+/* -------------- */
+ pseudo_bit_t reserved5[0x004c0];
+/* -------------- */
+};
+
+/* Event_data Field - ECC Detection Event */
+
+struct tavorprm_scrubbing_event_st { /* Little Endian */
+ pseudo_bit_t reserved0[0x00080];
+/* -------------- */
+ pseudo_bit_t cause_lsb[0x00001]; /* data integrity error cause:
+ single ECC error in the 64bit lsb data, on the rise edge of the clock */
+ pseudo_bit_t reserved1[0x00002];
+ pseudo_bit_t cause_msb[0x00001]; /* data integrity error cause:
+ single ECC error in the 64bit msb data, on the fall edge of the clock */
+ pseudo_bit_t reserved2[0x00002];
+ pseudo_bit_t err_rmw[0x00001]; /* transaction type:
+ 0 - read
+ 1 - read/modify/write */
+ pseudo_bit_t err_src_id[0x00003]; /* source of the transaction: 0x4 - PCI, other - internal or IB */
+ pseudo_bit_t err_da[0x00002]; /* Error DIMM address */
+ pseudo_bit_t err_ba[0x00002]; /* Error bank address */
+ pseudo_bit_t reserved3[0x00011];
+ pseudo_bit_t overflow[0x00001]; /* Fatal: ECC error FIFO overflow - ECC errors were detected, which may or may not have been corrected by InfiniHost */
+/* -------------- */
+ pseudo_bit_t err_ra[0x00010]; /* Error row address */
+ pseudo_bit_t err_ca[0x00010]; /* Error column address */
+/* -------------- */
+};
+
+/* PBL */
+
+struct tavorprm_pbl_st { /* Little Endian */
+ pseudo_bit_t mtt_0_h[0x00020]; /* First MTT[63:32] */
+/* -------------- */
+ pseudo_bit_t mtt_0_l[0x00020]; /* First MTT[31:0] */
+/* -------------- */
+ pseudo_bit_t mtt_1_h[0x00020]; /* Second MTT[63:32] */
+/* -------------- */
+ pseudo_bit_t mtt_1_l[0x00020]; /* Second MTT[31:0] */
+/* -------------- */
+ pseudo_bit_t mtt_2_h[0x00020]; /* Third MTT[63:32] */
+/* -------------- */
+ pseudo_bit_t mtt_2_l[0x00020]; /* Third MTT[31:0] */
+/* -------------- */
+ pseudo_bit_t mtt_3_h[0x00020]; /* Fourth MTT[63:32] */
+/* -------------- */
+ pseudo_bit_t mtt_3_l[0x00020]; /* Fourth MTT[31:0] */
+/* -------------- */
+};
+
+/* Miscellaneous Counters */
+
+struct tavorprm_misc_counters_st { /* Little Endian */
+ pseudo_bit_t ddr_scan_cnt[0x00020]; /* Number of times whole of DDR was scanned */
+/* -------------- */
+ pseudo_bit_t reserved0[0x007e0];
+/* -------------- */
+};
+
+/* MAD_IFC Opcode Modifier */
+
+struct tavorprm_mad_ifc_opcode_modifier_st { /* Little Endian */
+ pseudo_bit_t mkey[0x00001]; /* Enable MKey validation. */
+ pseudo_bit_t bkey[0x00001]; /* Enable BKey validation. */
+ pseudo_bit_t reserved0[0x0001d];
+ pseudo_bit_t mad_extended_info[0x00001];/* Mad_Extended_Info valid bit.
+ Requeried for for trap generation when BKey check is enabled. */
+/* -------------- */
+};
+
+/* MAD_IFC Input Modifier */
+
+struct tavorprm_mad_ifc_input_modifier_st { /* Little Endian */
+ pseudo_bit_t port_number[0x00008]; /* Port number (1 or 2). */
+ pseudo_bit_t reserved0[0x00008];
+ pseudo_bit_t rlid[0x00001]; /* Remote (source) LID from the received MAD.
+ This field is required for trap generation upon MKey/BKey validation. */
+ pseudo_bit_t reserved1[0x0000f];
+/* -------------- */
+};
+
+/* Fast_Registration_Segment */
+
+struct tavorprm_fast_registration_segment_st { /* Little Endian */
+ pseudo_bit_t reserved0[0x0001b];
+ pseudo_bit_t lr[0x00001]; /* If set - Local Read access will be enabled */
+ pseudo_bit_t lw[0x00001]; /* If set - Local Write access will be enabled */
+ pseudo_bit_t rr[0x00001]; /* If set - Remote Read access will be enabled */
+ pseudo_bit_t rw[0x00001]; /* If set - Remote Write access will be enabled */
+ pseudo_bit_t a[0x00001]; /* If set - Remote Atomic access will be enabled */
+/* -------------- */
+ pseudo_bit_t pbl_ptr_63_32[0x00020];/* Physical address pointer [63:32] to the physical block list */
+/* -------------- */
+ pseudo_bit_t mem_key[0x00020]; /* Memory Key on which the fast registration is executed on. */
+/* -------------- */
+ pseudo_bit_t page_size[0x00005]; /* Page size used for the region. Actual size is [4K]*2^Page_size bytes.
+ page_size should be less than 20. */
+ pseudo_bit_t reserved1[0x00002];
+ pseudo_bit_t zb[0x00001]; /* Zero Based Region */
+ pseudo_bit_t pbl_ptr_31_8[0x00018]; /* Physical address pointer [31:8] to the physical block list */
+/* -------------- */
+ pseudo_bit_t start_address_h[0x00020];/* Start Address[63:32] - Virtual Address where this region starts */
+/* -------------- */
+ pseudo_bit_t start_address_l[0x00020];/* Start Address[31:0] - Virtual Address where this region starts */
+/* -------------- */
+ pseudo_bit_t reg_len_h[0x00020]; /* Region Length[63:32] */
+/* -------------- */
+ pseudo_bit_t reg_len_l[0x00020]; /* Region Length[31:0] */
+/* -------------- */
+};
+
+/* 0 */
+
+struct tavorprm_tavor_prm_st { /* Little Endian */
+ struct tavorprm_completion_queue_entry_st completion_queue_entry;/* Completion Queue Entry Format */
+/* -------------- */
+ pseudo_bit_t reserved0[0x7ff00];
+/* -------------- */
+ struct tavorprm_qp_ee_state_transitions_st qp_ee_state_transitions;/* QP/EE State Transitions Command Parameters */
+/* -------------- */
+ pseudo_bit_t reserved1[0x7f000];
+/* -------------- */
+ struct tavorprm_event_queue_entry_st event_queue_entry;/* Event Queue Entry */
+/* -------------- */
+ pseudo_bit_t reserved2[0x7ff00];
+/* -------------- */
+ struct tavorprm_completion_event_st completion_event;/* Event_data Field - Completion Event */
+/* -------------- */
+ pseudo_bit_t reserved3[0x7ff40];
+/* -------------- */
+ struct tavorprm_completion_queue_error_st completion_queue_error;/* Event_data Field - Completion Queue Error */
+/* -------------- */
+ pseudo_bit_t reserved4[0x7ff40];
+/* -------------- */
+ struct tavorprm_port_state_change_st port_state_change;/* Event_data Field - Port State Change */
+/* -------------- */
+ pseudo_bit_t reserved5[0xfff40];
+/* -------------- */
+ struct tavorprm_page_fault_event_data_st page_fault_event_data;/* Event_data Field - Page Faults */
+/* -------------- */
+ pseudo_bit_t reserved6[0x7ff40];
+/* -------------- */
+ struct tavorprm_performance_monitor_event_st performance_monitor_event;/* Event Data Field - Performance Monitor */
+/* -------------- */
+ pseudo_bit_t reserved7[0x7ff20];
+/* -------------- */
+ struct tavorprm_ntu_qpm_st ntu_qpm; /* NTU QP Map Table Entry */
+/* -------------- */
+ pseudo_bit_t reserved8[0x7ff80];
+/* -------------- */
+ struct tavorprm_mt23108_type0_st mt23108_type0;/* InfiniHost Type0 Configuration Header */
+/* -------------- */
+ pseudo_bit_t reserved9[0x7f800];
+/* -------------- */
+ struct tavorprm_qp_ee_event_st qp_ee_event;/* Event_data Field - QP/EE Events */
+/* -------------- */
+ pseudo_bit_t reserved10[0x00040];
+/* -------------- */
+ struct tavorprm_gpio_event_data_st gpio_event_data;
+/* -------------- */
+ pseudo_bit_t reserved11[0x7fe40];
+/* -------------- */
+ struct tavorprm_ud_address_vector_st ud_address_vector;/* UD Address Vector */
+/* -------------- */
+ pseudo_bit_t reserved12[0x7ff00];
+/* -------------- */
+ struct tavorprm_queue_pair_ee_context_entry_st queue_pair_ee_context_entry;/* QP and EE Context Entry */
+/* -------------- */
+ pseudo_bit_t reserved13[0x7f800];
+/* -------------- */
+ struct tavorprm_address_path_st address_path;/* Address Path */
+/* -------------- */
+ pseudo_bit_t reserved14[0x7ff00];
+/* -------------- */
+ struct tavorprm_completion_queue_context_st completion_queue_context;/* Completion Queue Context Table Entry */
+/* -------------- */
+ pseudo_bit_t reserved15[0x7fe00];
+/* -------------- */
+ struct tavorprm_mpt_st mpt; /* Memory Protection Table (MPT) Entry */
+/* -------------- */
+ pseudo_bit_t reserved16[0x7fe00];
+/* -------------- */
+ struct tavorprm_mtt_st mtt; /* Memory Translation Table (MTT) Entry */
+/* -------------- */
+ pseudo_bit_t reserved17[0x7ffc0];
+/* -------------- */
+ struct tavorprm_eqc_st eqc; /* Event Queue Context Table Entry */
+/* -------------- */
+ pseudo_bit_t reserved18[0x7fe00];
+/* -------------- */
+ struct tavorprm_performance_monitors_st performance_monitors;/* Performance Monitors */
+/* -------------- */
+ pseudo_bit_t reserved19[0x7ff80];
+/* -------------- */
+ struct tavorprm_hca_command_register_st hca_command_register;/* HCA Command Register (HCR) */
+/* -------------- */
+ pseudo_bit_t reserved20[0xfff20];
+/* -------------- */
+ struct tavorprm_init_hca_st init_hca;/* INIT_HCA & QUERY_HCA Parameters Block */
+/* -------------- */
+ pseudo_bit_t reserved21[0x7f000];
+/* -------------- */
+ struct tavorprm_qpcbaseaddr_st qpcbaseaddr;/* QPC/EEC/CQC/EQC/RDB Parameters */
+/* -------------- */
+ pseudo_bit_t reserved22[0x7fc00];
+/* -------------- */
+ struct tavorprm_udavtable_memory_parameters_st udavtable_memory_parameters;/* Memory Access Parameters for UD Address Vector Table */
+/* -------------- */
+ pseudo_bit_t reserved23[0x7ffc0];
+/* -------------- */
+ struct tavorprm_multicastparam_st multicastparam;/* Multicast Support Parameters */
+/* -------------- */
+ pseudo_bit_t reserved24[0x7ff00];
+/* -------------- */
+ struct tavorprm_tptparams_st tptparams;/* Translation and Protection Tables Parameters */
+/* -------------- */
+ pseudo_bit_t reserved25[0x7ff00];
+/* -------------- */
+ struct tavorprm_query_ddr_st query_ddr;/* QUERY_DDR Parameters Block */
+/* -------------- */
+ struct tavorprm_access_ddr_st access_ddr;
+/* -------------- */
+ pseudo_bit_t reserved26[0x7f700];
+/* -------------- */
+ struct tavorprm_dimminfo_st dimminfo;/* Logical DIMM Information */
+/* -------------- */
+ pseudo_bit_t reserved27[0x7ff00];
+/* -------------- */
+ struct tavorprm_query_fw_st query_fw;/* QUERY_FW Parameters Block */
+/* -------------- */
+ pseudo_bit_t reserved28[0x7f800];
+/* -------------- */
+ struct tavorprm_query_adapter_st query_adapter;/* QUERY_ADAPTER Parameters Block */
+/* -------------- */
+ pseudo_bit_t reserved29[0x7f800];
+/* -------------- */
+ struct tavorprm_query_dev_lim_st query_dev_lim;/* Query Device Limitations */
+/* -------------- */
+ pseudo_bit_t reserved30[0x7f800];
+/* -------------- */
+ struct tavorprm_uar_params_st uar_params;/* UAR Parameters */
+/* -------------- */
+ pseudo_bit_t reserved31[0x7ff00];
+/* -------------- */
+ struct tavorprm_init_ib_st init_ib; /* INIT_IB Parameters */
+/* -------------- */
+ pseudo_bit_t reserved32[0x7f800];
+/* -------------- */
+ struct tavorprm_mgm_entry_st mgm_entry;/* Multicast Group Member */
+/* -------------- */
+ pseudo_bit_t reserved33[0x7fe00];
+/* -------------- */
+ struct tavorprm_set_ib_st set_ib; /* SET_IB Parameters */
+/* -------------- */
+ pseudo_bit_t reserved34[0x7fe00];
+/* -------------- */
+ struct tavorprm_rd_send_doorbell_st rd_send_doorbell;/* RD-send doorbell */
+/* -------------- */
+ pseudo_bit_t reserved35[0x7ff80];
+/* -------------- */
+ struct tavorprm_send_doorbell_st send_doorbell;/* Send doorbell */
+/* -------------- */
+ pseudo_bit_t reserved36[0x7ffc0];
+/* -------------- */
+ struct tavorprm_receive_doorbell_st receive_doorbell;/* Receive doorbell */
+/* -------------- */
+ pseudo_bit_t reserved37[0x7ffc0];
+/* -------------- */
+ struct tavorprm_cq_cmd_doorbell_st cq_cmd_doorbell;/* CQ Doorbell */
+/* -------------- */
+ pseudo_bit_t reserved38[0x7ffc0];
+/* -------------- */
+ struct tavorprm_eq_cmd_doorbell_st eq_cmd_doorbell;/* EQ Doorbell */
+/* -------------- */
+ pseudo_bit_t reserved39[0x7ffc0];
+/* -------------- */
+ struct tavorprm_uar_st uar; /* User Access Region */
+/* -------------- */
+ pseudo_bit_t reserved40[0x7c000];
+/* -------------- */
+ struct tavorprm_mgmqp_st mgmqp; /* Multicast Group Member QP */
+/* -------------- */
+ pseudo_bit_t reserved41[0x7ffe0];
+/* -------------- */
+ struct tavorprm_query_debug_msg_st query_debug_msg;/* Query Debug Message */
+/* -------------- */
+ pseudo_bit_t reserved42[0x7f800];
+/* -------------- */
+ struct tavorprm_sys_en_out_param_st sys_en_out_param;/* SYS_EN Output Parameter */
+/* -------------- */
+ pseudo_bit_t reserved43[0x7ffc0];
+/* -------------- */
+ struct tavorprm_resize_cq_st resize_cq;/* Resize CQ Input Mailbox */
+/* -------------- */
+ pseudo_bit_t reserved44[0x7fe00];
+/* -------------- */
+ struct tavorprm_completion_with_error_st completion_with_error;/* Completion with Error CQE */
+/* -------------- */
+ pseudo_bit_t reserved45[0x7ff00];
+/* -------------- */
+ struct tavorprm_hcr_completion_event_st hcr_completion_event;/* Event_data Field - HCR Completion Event */
+/* -------------- */
+ pseudo_bit_t reserved46[0x7ff40];
+/* -------------- */
+ struct tavorprm_transport_and_ci_error_counters_st transport_and_ci_error_counters;/* Transport and CI Error Counters */
+/* -------------- */
+ pseudo_bit_t reserved47[0x7f000];
+/* -------------- */
+ struct tavorprm_performance_counters_st performance_counters;/* Performance Counters */
+/* -------------- */
+ pseudo_bit_t reserved48[0x7f800];
+/* -------------- */
+ struct tavorprm_query_bar_st query_bar;/* Query BAR */
+/* -------------- */
+ pseudo_bit_t reserved49[0x7ffc0];
+/* -------------- */
+ struct tavorprm_cfg_schq_st cfg_schq;/* Schedule queues configuration */
+/* -------------- */
+ pseudo_bit_t reserved50[0x7f800];
+/* -------------- */
+ struct tavorprm_mt23108_configuration_registers_st mt23108_configuration_registers;/* InfiniHost Configuration Registers - Used in Mem-Free mode only */
+/* -------------- */
+ pseudo_bit_t reserved51[0x80000];
+/* -------------- */
+ pseudo_bit_t reserved52[0x00100];
+/* -------------- */
+ pseudo_bit_t reserved53[0x7ff00];
+/* -------------- */
+ pseudo_bit_t reserved54[0x00100];
+/* -------------- */
+ pseudo_bit_t reserved55[0x7ff00];
+/* -------------- */
+ struct tavorprm_srq_context_st srq_context;/* SRQ Context */
+/* -------------- */
+ pseudo_bit_t reserved56[0x7ff00];
+/* -------------- */
+ struct tavorprm_mod_stat_cfg_st mod_stat_cfg;/* MOD_STAT_CFG */
+/* -------------- */
+ pseudo_bit_t reserved57[0x00080];
+/* -------------- */
+ pseudo_bit_t reserved58[0x00040];
+/* -------------- */
+ pseudo_bit_t reserved59[0x1bff740];
+/* -------------- */
+};
+
+#include "MT23108_PRM_append.h"
+
+#endif /* H_prefix_tavorprm_bits_fixnames_MT23108_PRM_csp_H */
diff --git a/src/drivers/net/mlx_ipoib/MT23108_PRM_append.h b/src/drivers/net/mlx_ipoib/MT23108_PRM_append.h
new file mode 100644
index 000000000..e8b6bc5d4
--- /dev/null
+++ b/src/drivers/net/mlx_ipoib/MT23108_PRM_append.h
@@ -0,0 +1,199 @@
+/*
+ This software is available to you under a choice of one of two
+ licenses. You may choose to be licensed under the terms of the GNU
+ General Public License (GPL) Version 2, available at
+ <http://www.fsf.org/copyleft/gpl.html>, or the OpenIB.org BSD
+ license, available in the LICENSE.TXT file accompanying this
+ software. These details are also available at
+ <http://openib.org/license.html>.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+
+ Copyright (c) 2004 Mellanox Technologies Ltd. All rights reserved.
+*/
+
+/***
+ *** This file was generated at "Tue Nov 16 17:03:53 2004"
+ *** by:
+ *** % csp_bf -copyright=/mswg/misc/license-header.txt -bits MT23108_PRM_append.csp
+ ***/
+
+#ifndef H_bits_MT23108_PRM_append_csp_H
+#define H_bits_MT23108_PRM_append_csp_H
+
+
+/* Gather entry with inline data */
+
+struct wqe_segment_data_inline_st { /* Little Endian */
+ pseudo_bit_t byte_count[0x0000a]; /* Not including padding for 16Byte chunks */
+ pseudo_bit_t reserved0[0x00015];
+ pseudo_bit_t always1[0x00001];
+/* -------------- */
+ pseudo_bit_t data[0x00020]; /* Data may be more this segment size - in 16Byte chunks */
+/* -------------- */
+};
+
+/* Scatter/Gather entry with a pointer */
+
+struct wqe_segment_data_ptr_st { /* Little Endian */
+ pseudo_bit_t byte_count[0x0001f];
+ pseudo_bit_t always0[0x00001];
+/* -------------- */
+ pseudo_bit_t l_key[0x00020];
+/* -------------- */
+ pseudo_bit_t local_address_h[0x00020];
+/* -------------- */
+ pseudo_bit_t local_address_l[0x00020];
+/* -------------- */
+};
+
+/* */
+
+struct wqe_segment_atomic_st { /* Little Endian */
+ pseudo_bit_t swap_add_h[0x00020];
+/* -------------- */
+ pseudo_bit_t swap_add_l[0x00020];
+/* -------------- */
+ pseudo_bit_t compare_h[0x00020];
+/* -------------- */
+ pseudo_bit_t compare_l[0x00020];
+/* -------------- */
+};
+
+/* */
+
+struct wqe_segment_remote_address_st { /* Little Endian */
+ pseudo_bit_t remote_virt_addr_h[0x00020];
+/* -------------- */
+ pseudo_bit_t remote_virt_addr_l[0x00020];
+/* -------------- */
+ pseudo_bit_t rkey[0x00020];
+/* -------------- */
+ pseudo_bit_t reserved0[0x00020];
+/* -------------- */
+};
+
+/* Bind memory window segment */
+
+struct wqe_segment_bind_st { /* Little Endian */
+ pseudo_bit_t reserved0[0x0001d];
+ pseudo_bit_t rr[0x00001]; /* Remote read */
+ pseudo_bit_t rw[0x00001]; /* Remote write */
+ pseudo_bit_t a[0x00001]; /* atomic */
+/* -------------- */
+ pseudo_bit_t reserved1[0x00020];
+/* -------------- */
+ pseudo_bit_t new_rkey[0x00020];
+/* -------------- */
+ pseudo_bit_t region_lkey[0x00020];
+/* -------------- */
+ pseudo_bit_t start_address_h[0x00020];
+/* -------------- */
+ pseudo_bit_t start_address_l[0x00020];
+/* -------------- */
+ pseudo_bit_t length_h[0x00020];
+/* -------------- */
+ pseudo_bit_t length_l[0x00020];
+/* -------------- */
+};
+
+/* */
+
+struct wqe_segment_ud_st { /* Little Endian */
+ pseudo_bit_t reserved0[0x00020];
+/* -------------- */
+ pseudo_bit_t l_key[0x00020]; /* memory key for UD AV */
+/* -------------- */
+ pseudo_bit_t av_address_63_32[0x00020];
+/* -------------- */
+ pseudo_bit_t reserved1[0x00005];
+ pseudo_bit_t av_address_31_5[0x0001b];
+/* -------------- */
+ pseudo_bit_t reserved2[0x00080];
+/* -------------- */
+ pseudo_bit_t destination_qp[0x00018];
+ pseudo_bit_t reserved3[0x00008];
+/* -------------- */
+ pseudo_bit_t q_key[0x00020];
+/* -------------- */
+ pseudo_bit_t reserved4[0x00040];
+/* -------------- */
+};
+
+/* */
+
+struct wqe_segment_rd_st { /* Little Endian */
+ pseudo_bit_t destination_qp[0x00018];
+ pseudo_bit_t reserved0[0x00008];
+/* -------------- */
+ pseudo_bit_t q_key[0x00020];
+/* -------------- */
+ pseudo_bit_t reserved1[0x00040];
+/* -------------- */
+};
+
+/* */
+
+struct wqe_segment_ctrl_recv_st { /* Little Endian */
+ pseudo_bit_t reserved0[0x00002];
+ pseudo_bit_t e[0x00001]; /* WQE event */
+ pseudo_bit_t c[0x00001]; /* Create CQE (for "requested signalling" QP) */
+ pseudo_bit_t reserved1[0x0001c];
+/* -------------- */
+ pseudo_bit_t reserved2[0x00020];
+/* -------------- */
+};
+
+/* */
+
+struct wqe_segment_ctrl_mlx_st { /* Little Endian */
+ pseudo_bit_t reserved0[0x00002];
+ pseudo_bit_t e[0x00001]; /* WQE event */
+ pseudo_bit_t c[0x00001]; /* Create CQE (for "requested signalling" QP) */
+ pseudo_bit_t reserved1[0x00004];
+ pseudo_bit_t sl[0x00004];
+ pseudo_bit_t max_statrate[0x00003];
+ pseudo_bit_t reserved2[0x00001];
+ pseudo_bit_t slr[0x00001]; /* 0= take slid from port. 1= take slid from given headers */
+ pseudo_bit_t v15[0x00001]; /* Send packet over VL15 */
+ pseudo_bit_t reserved3[0x0000e];
+/* -------------- */
+ pseudo_bit_t vcrc[0x00010]; /* Packet's VCRC (if not 0 - otherwise computed by HW) */
+ pseudo_bit_t rlid[0x00010]; /* Destination LID (must match given headers) */
+/* -------------- */
+};
+
+/* */
+
+struct wqe_segment_ctrl_send_st { /* Little Endian */
+ pseudo_bit_t always1[0x00001];
+ pseudo_bit_t s[0x00001]; /* Solicited event */
+ pseudo_bit_t e[0x00001]; /* WQE event */
+ pseudo_bit_t c[0x00001]; /* Create CQE (for "requested signalling" QP) */
+ pseudo_bit_t reserved0[0x0001c];
+/* -------------- */
+ pseudo_bit_t immediate[0x00020];
+/* -------------- */
+};
+
+/* */
+
+struct wqe_segment_next_st { /* Little Endian */
+ pseudo_bit_t nopcode[0x00005]; /* next opcode */
+ pseudo_bit_t reserved0[0x00001];
+ pseudo_bit_t nda_31_6[0x0001a]; /* NDA[31:6] */
+/* -------------- */
+ pseudo_bit_t nds[0x00006];
+ pseudo_bit_t f[0x00001]; /* fence bit */
+ pseudo_bit_t dbd[0x00001]; /* doorbell rung */
+ pseudo_bit_t nee[0x00018]; /* next EE */
+/* -------------- */
+};
+#endif /* H_bits_MT23108_PRM_append_csp_H */
diff --git a/src/drivers/net/mlx_ipoib/MT25218_PRM.h b/src/drivers/net/mlx_ipoib/MT25218_PRM.h
new file mode 100644
index 000000000..e0eae3854
--- /dev/null
+++ b/src/drivers/net/mlx_ipoib/MT25218_PRM.h
@@ -0,0 +1,3463 @@
+/*
+ This software is available to you under a choice of one of two
+ licenses. You may choose to be licensed under the terms of the GNU
+ General Public License (GPL) Version 2, available at
+ <http://www.fsf.org/copyleft/gpl.html>, or the OpenIB.org BSD
+ license, available in the LICENSE.TXT file accompanying this
+ software. These details are also available at
+ <http://openib.org/license.html>.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+
+ Copyright (c) 2004 Mellanox Technologies Ltd. All rights reserved.
+*/
+
+/***
+ *** This file was generated at "Tue Nov 22 15:21:23 2005"
+ *** by:
+ *** % csp_bf -copyright=/mswg/misc/license-header.txt -prefix arbelprm_ -bits -fixnames MT25218_PRM.csp
+ ***/
+
+#ifndef H_prefix_arbelprm_bits_fixnames_MT25218_PRM_csp_H
+#define H_prefix_arbelprm_bits_fixnames_MT25218_PRM_csp_H
+
+#include "bit_ops.h"
+
+
+/* UD Address Vector */
+
+struct arbelprm_ud_address_vector_st { /* Little Endian */
+ pseudo_bit_t pd[0x00018]; /* Protection Domain */
+ pseudo_bit_t port_number[0x00002]; /* Port number
+ 1 - Port 1
+ 2 - Port 2
+ other - reserved */
+ pseudo_bit_t reserved0[0x00006];
+/* -------------- */
+ pseudo_bit_t rlid[0x00010]; /* Remote (Destination) LID */
+ pseudo_bit_t my_lid_path_bits[0x00007];/* Source LID - the lower 7 bits (upper bits are taken from PortInfo) */
+ pseudo_bit_t g[0x00001]; /* Global address enable - if set, GRH will be formed for packet header */
+ pseudo_bit_t reserved1[0x00008];
+/* -------------- */
+ pseudo_bit_t hop_limit[0x00008]; /* IPv6 hop limit */
+ pseudo_bit_t max_stat_rate[0x00003];/* Maximum static rate control.
+ 0 - 4X injection rate
+ 1 - 1X injection rate
+ other - reserved
+ */
+ pseudo_bit_t reserved2[0x00001];
+ pseudo_bit_t msg[0x00002]; /* Max Message size, size is 256*2^MSG bytes */
+ pseudo_bit_t reserved3[0x00002];
+ pseudo_bit_t mgid_index[0x00006]; /* Index to port GID table
+ mgid_index = (port_number-1) * 2^log_max_gid + gid_index
+ Where:
+ 1. log_max_gid is taken from QUERY_DEV_LIM command
+ 2. gid_index is the index to the GID table */
+ pseudo_bit_t reserved4[0x0000a];
+/* -------------- */
+ pseudo_bit_t flow_label[0x00014]; /* IPv6 flow label */
+ pseudo_bit_t tclass[0x00008]; /* IPv6 TClass */
+ pseudo_bit_t sl[0x00004]; /* InfiniBand Service Level (SL) */
+/* -------------- */
+ pseudo_bit_t rgid_127_96[0x00020]; /* Remote GID[127:96] */
+/* -------------- */
+ pseudo_bit_t rgid_95_64[0x00020]; /* Remote GID[95:64] */
+/* -------------- */
+ pseudo_bit_t rgid_63_32[0x00020]; /* Remote GID[63:32] */
+/* -------------- */
+ pseudo_bit_t rgid_31_0[0x00020]; /* Remote GID[31:0] if G bit is set. Must be set to 0x2 if G bit is cleared. */
+/* -------------- */
+};
+
+/* Send doorbell */
+
+struct arbelprm_send_doorbell_st { /* Little Endian */
+ pseudo_bit_t nopcode[0x00005]; /* Opcode of descriptor to be executed */
+ pseudo_bit_t f[0x00001]; /* Fence bit. If set, descriptor is fenced */
+ pseudo_bit_t reserved0[0x00002];
+ pseudo_bit_t wqe_counter[0x00010]; /* Modulo-64K counter of WQEs posted to the QP since its creation excluding the newly posted WQEs in this doorbell. Should be zero for the first doorbell on the QP */
+ pseudo_bit_t wqe_cnt[0x00008]; /* Number of WQEs posted with this doorbell. Must be grater then zero. */
+/* -------------- */
+ pseudo_bit_t nds[0x00006]; /* Next descriptor size (in 16-byte chunks) */
+ pseudo_bit_t reserved1[0x00002];
+ pseudo_bit_t qpn[0x00018]; /* QP number this doorbell is rung on */
+/* -------------- */
+};
+
+/* ACCESS_LAM_inject_errors_input_modifier */
+
+struct arbelprm_access_lam_inject_errors_input_modifier_st { /* Little Endian */
+ pseudo_bit_t index3[0x00007];
+ pseudo_bit_t q3[0x00001];
+ pseudo_bit_t index2[0x00007];
+ pseudo_bit_t q2[0x00001];
+ pseudo_bit_t index1[0x00007];
+ pseudo_bit_t q1[0x00001];
+ pseudo_bit_t index0[0x00007];
+ pseudo_bit_t q0[0x00001];
+/* -------------- */
+};
+
+/* ACCESS_LAM_inject_errors_input_parameter */
+
+struct arbelprm_access_lam_inject_errors_input_parameter_st { /* Little Endian */
+ pseudo_bit_t ba[0x00002]; /* Bank Address */
+ pseudo_bit_t da[0x00002]; /* Dimm Address */
+ pseudo_bit_t reserved0[0x0001c];
+/* -------------- */
+ pseudo_bit_t ra[0x00010]; /* Row Address */
+ pseudo_bit_t ca[0x00010]; /* Column Address */
+/* -------------- */
+};
+
+/* */
+
+struct arbelprm_recv_wqe_segment_next_st { /* Little Endian */
+ pseudo_bit_t reserved0[0x00006];
+ pseudo_bit_t nda_31_6[0x0001a]; /* Next WQE address, low 32 bit. WQE address must be aligned to 64-byte boundary (6 LSB are forced ZERO). */
+/* -------------- */
+ pseudo_bit_t nds[0x00006]; /* Next WQE size in OctoWords (16 bytes).
+ Zero value in NDS field signals end of WQEs? chain.
+ */
+ pseudo_bit_t reserved1[0x0001a];
+/* -------------- */
+};
+
+/* Send wqe segment data inline */
+
+struct arbelprm_wqe_segment_data_inline_st { /* Little Endian */
+ pseudo_bit_t byte_count[0x0000a]; /* Not including padding for 16Byte chunks */
+ pseudo_bit_t reserved0[0x00015];
+ pseudo_bit_t always1[0x00001];
+/* -------------- */
+ pseudo_bit_t data[0x00018]; /* Data may be more this segment size - in 16Byte chunks */
+ pseudo_bit_t reserved1[0x00008];
+/* -------------- */
+ pseudo_bit_t reserved2[0x00040];
+/* -------------- */
+};
+
+/* Send wqe segment data ptr */
+
+struct arbelprm_wqe_segment_data_ptr_st { /* Little Endian */
+ pseudo_bit_t byte_count[0x0001f];
+ pseudo_bit_t always0[0x00001];
+/* -------------- */
+ pseudo_bit_t l_key[0x00020];
+/* -------------- */
+ pseudo_bit_t local_address_h[0x00020];
+/* -------------- */
+ pseudo_bit_t local_address_l[0x00020];
+/* -------------- */
+};
+
+/* Send wqe segment rd */
+
+struct arbelprm_local_invalidate_segment_st { /* Little Endian */
+ pseudo_bit_t reserved0[0x00040];
+/* -------------- */
+ pseudo_bit_t mem_key[0x00018];
+ pseudo_bit_t reserved1[0x00008];
+/* -------------- */
+ pseudo_bit_t reserved2[0x000a0];
+/* -------------- */
+};
+
+/* Fast_Registration_Segment */
+
+struct arbelprm_fast_registration_segment_st { /* Little Endian */
+ pseudo_bit_t reserved0[0x0001b];
+ pseudo_bit_t lr[0x00001]; /* If set - Local Read access will be enabled */
+ pseudo_bit_t lw[0x00001]; /* If set - Local Write access will be enabled */
+ pseudo_bit_t rr[0x00001]; /* If set - Remote Read access will be enabled */
+ pseudo_bit_t rw[0x00001]; /* If set - Remote Write access will be enabled */
+ pseudo_bit_t a[0x00001]; /* If set - Remote Atomic access will be enabled */
+/* -------------- */
+ pseudo_bit_t pbl_ptr_63_32[0x00020];/* Physical address pointer [63:32] to the physical buffer list */
+/* -------------- */
+ pseudo_bit_t mem_key[0x00020]; /* Memory Key on which the fast registration is executed on. */
+/* -------------- */
+ pseudo_bit_t page_size[0x00005]; /* Page size used for the region. Actual size is [4K]*2^Page_size bytes.
+ page_size should be less than 20. */
+ pseudo_bit_t reserved1[0x00002];
+ pseudo_bit_t zb[0x00001]; /* Zero Based Region */
+ pseudo_bit_t pbl_ptr_31_8[0x00018]; /* Physical address pointer [31:8] to the physical buffer list */
+/* -------------- */
+ pseudo_bit_t start_address_h[0x00020];/* Start Address[63:32] - Virtual Address where this region starts */
+/* -------------- */
+ pseudo_bit_t start_address_l[0x00020];/* Start Address[31:0] - Virtual Address where this region starts */
+/* -------------- */
+ pseudo_bit_t reg_len_h[0x00020]; /* Region Length[63:32] */
+/* -------------- */
+ pseudo_bit_t reg_len_l[0x00020]; /* Region Length[31:0] */
+/* -------------- */
+};
+
+/* Send wqe segment atomic */
+
+struct arbelprm_wqe_segment_atomic_st { /* Little Endian */
+ pseudo_bit_t swap_add_h[0x00020];
+/* -------------- */
+ pseudo_bit_t swap_add_l[0x00020];
+/* -------------- */
+ pseudo_bit_t compare_h[0x00020];
+/* -------------- */
+ pseudo_bit_t compare_l[0x00020];
+/* -------------- */
+};
+
+/* Send wqe segment remote address */
+
+struct arbelprm_wqe_segment_remote_address_st { /* Little Endian */
+ pseudo_bit_t remote_virt_addr_h[0x00020];
+/* -------------- */
+ pseudo_bit_t remote_virt_addr_l[0x00020];
+/* -------------- */
+ pseudo_bit_t rkey[0x00020];
+/* -------------- */
+ pseudo_bit_t reserved0[0x00020];
+/* -------------- */
+};
+
+/* end wqe segment bind */
+
+struct arbelprm_wqe_segment_bind_st { /* Little Endian */
+ pseudo_bit_t reserved0[0x0001d];
+ pseudo_bit_t rr[0x00001]; /* If set, Remote Read Enable for bound window. */
+ pseudo_bit_t rw[0x00001]; /* If set, Remote Write Enable for bound window.
+ */
+ pseudo_bit_t a[0x00001]; /* If set, Atomic Enable for bound window. */
+/* -------------- */
+ pseudo_bit_t reserved1[0x0001e];
+ pseudo_bit_t zb[0x00001]; /* If set, Window is Zero Based. */
+ pseudo_bit_t type[0x00001]; /* Window type.
+ 0 - Type one window
+ 1 - Type two window
+ */
+/* -------------- */
+ pseudo_bit_t new_rkey[0x00020]; /* The new RKey of window to bind */
+/* -------------- */
+ pseudo_bit_t region_lkey[0x00020]; /* Local key of region, which window will be bound to */
+/* -------------- */
+ pseudo_bit_t start_address_h[0x00020];
+/* -------------- */
+ pseudo_bit_t start_address_l[0x00020];
+/* -------------- */
+ pseudo_bit_t length_h[0x00020];
+/* -------------- */
+ pseudo_bit_t length_l[0x00020];
+/* -------------- */
+};
+
+/* Send wqe segment ud */
+
+struct arbelprm_wqe_segment_ud_st { /* Little Endian */
+ struct arbelprm_ud_address_vector_st ud_address_vector;/* UD Address Vector */
+/* -------------- */
+ pseudo_bit_t destination_qp[0x00018];
+ pseudo_bit_t reserved0[0x00008];
+/* -------------- */
+ pseudo_bit_t q_key[0x00020];
+/* -------------- */
+ pseudo_bit_t reserved1[0x00040];
+/* -------------- */
+};
+
+/* Send wqe segment rd */
+
+struct arbelprm_wqe_segment_rd_st { /* Little Endian */
+ pseudo_bit_t destination_qp[0x00018];
+ pseudo_bit_t reserved0[0x00008];
+/* -------------- */
+ pseudo_bit_t q_key[0x00020];
+/* -------------- */
+ pseudo_bit_t reserved1[0x00040];
+/* -------------- */
+};
+
+/* Send wqe segment ctrl */
+
+struct arbelprm_wqe_segment_ctrl_send_st { /* Little Endian */
+ pseudo_bit_t always1[0x00001];
+ pseudo_bit_t s[0x00001]; /* Solicited Event bit. If set, SE (Solicited Event) bit is set in the (last packet of) message. */
+ pseudo_bit_t e[0x00001]; /* Event bit. If set, event is generated upon WQE?s completion, if QP is allowed to generate an event. Every WQE with E-bit set generates an event. The C bit must be set on unsignalled QPs if the E bit is set. */
+ pseudo_bit_t c[0x00001]; /* Completion Queue bit. Valid for unsignalled QPs only. If set, the CQ is updated upon WQE?s completion */
+ pseudo_bit_t ip[0x00001]; /* When set, InfiniHost III Ex will calculate the IP checksum of the IP header that is present immediately after the IPoverIB encapsulation header. In the case of multiple headers (encapsulation), InfiniHost III Ex will calculate the checksum only for the first IP header following the IPoverIB encapsulation header. Not Valid for IPv6 packets */
+ pseudo_bit_t tcp_udp[0x00001]; /* When set, InfiniHost III Ex will calculate the TCP/UDP checksum of the packet that is present immediately after the IP header. In the case of multiple headers (encapsulation), InfiniHost III Ex will calculate the checksum only for the first TCP header following the IP header. This bit may be set only if the entire TCP/UDP segment is present in one IB packet */
+ pseudo_bit_t reserved0[0x00001];
+ pseudo_bit_t so[0x00001]; /* Strong Ordering - when set, the WQE will be executed only after all previous WQEs have been executed. Can be set for RC WQEs only. This bit must be set in type two BIND, Fast Registration and Local invalidate operations. */
+ pseudo_bit_t reserved1[0x00018];
+/* -------------- */
+ pseudo_bit_t immediate[0x00020]; /* If the OpCode encodes an operation with Immediate (RDMA-write/SEND), This field will hold the Immediate data to be sent. If the OpCode encodes send and invalidate operations, this field holds the Invalidation key to be inserted into the packet; otherwise, this field is reserved. */
+/* -------------- */
+};
+
+/* Send wqe segment next */
+
+struct arbelprm_wqe_segment_next_st { /* Little Endian */
+ pseudo_bit_t nopcode[0x00005]; /* Next Opcode: OpCode to be used in the next WQE. Encodes the type of operation to be executed on the QP:
+ ?00000? - NOP. WQE with this opcode creates a completion, but does nothing else
+ ?01000? - RDMA-write
+ ?01001? - RDMA-Write with Immediate
+ ?10000? - RDMA-read
+ ?10001? - Atomic Compare & swap
+ ?10010? - Atomic Fetch & Add
+ ?11000? - Bind memory window
+
+ The encoding for the following operations depends on the QP type:
+ For RC, UC and RD QP:
+ ?01010? - SEND
+ ?01011? - SEND with Immediate
+
+ For UD QP:
+ the encoding depends on the values of bit[31] of the Q_key field in the Datagram Segment (see Table 39, ?Unreliable Datagram Segment Format - Pointers,? on page 101) of
+ both the current WQE and the next WQE, as follows:
+
+ If the last WQE Q_Key bit[31] is clear and the next WQE Q_key bit[31] is set :
+ ?01000? - SEND
+ ?01001? - SEND with Immediate
+
+ otherwise (if the next WQE Q_key bit[31] is cleared, or the last WQE Q_Key bit[31] is set):
+ ?01010? - SEND
+ ?01011? - SEND with Immediate
+
+ All other opcode values are RESERVED, and will result in invalid operation execution. */
+ pseudo_bit_t reserved0[0x00001];
+ pseudo_bit_t nda_31_6[0x0001a]; /* Next WQE address, low 32 bit. WQE address must be aligned to 64-byte boundary (6 LSB are forced ZERO). */
+/* -------------- */
+ pseudo_bit_t nds[0x00006]; /* Next WQE size in OctoWords (16 bytes).
+ Zero value in NDS field signals end of WQEs? chain.
+ */
+ pseudo_bit_t f[0x00001]; /* Fence bit. If set, next WQE will start execution only after all previous Read/Atomic WQEs complete. */
+ pseudo_bit_t always1[0x00001];
+ pseudo_bit_t reserved1[0x00018];
+/* -------------- */
+};
+
+/* Address Path */
+
+struct arbelprm_address_path_st { /* Little Endian */
+ pseudo_bit_t pkey_index[0x00007]; /* PKey table index */
+ pseudo_bit_t reserved0[0x00011];
+ pseudo_bit_t port_number[0x00002]; /* Specific port associated with this QP/EE.
+ 1 - Port 1
+ 2 - Port 2
+ other - reserved */
+ pseudo_bit_t reserved1[0x00006];
+/* -------------- */
+ pseudo_bit_t rlid[0x00010]; /* Remote (Destination) LID */
+ pseudo_bit_t my_lid_path_bits[0x00007];/* Source LID - the lower 7 bits (upper bits are taken from PortInfo) */
+ pseudo_bit_t g[0x00001]; /* Global address enable - if set, GRH will be formed for packet header */
+ pseudo_bit_t reserved2[0x00005];
+ pseudo_bit_t rnr_retry[0x00003]; /* RNR retry count (see C9-132 in IB spec Vol 1)
+ 0-6 - number of retries
+ 7 - infinite */
+/* -------------- */
+ pseudo_bit_t hop_limit[0x00008]; /* IPv6 hop limit */
+ pseudo_bit_t max_stat_rate[0x00003];/* Maximum static rate control.
+ 0 - 100% injection rate
+ 1 - 25% injection rate
+ 2 - 12.5% injection rate
+ 3 - 50% injection rate
+ other - reserved */
+ pseudo_bit_t reserved3[0x00005];
+ pseudo_bit_t mgid_index[0x00006]; /* Index to port GID table */
+ pseudo_bit_t reserved4[0x00005];
+ pseudo_bit_t ack_timeout[0x00005]; /* Local ACK timeout - Transport timer for activation of retransmission mechanism. Refer to IB spec Vol1 9.7.6.1.3 for further details.
+ The transport timer is set to 4.096us*2^ack_timeout, if ack_timeout is 0 then transport timer is disabled. */
+/* -------------- */
+ pseudo_bit_t flow_label[0x00014]; /* IPv6 flow label */
+ pseudo_bit_t tclass[0x00008]; /* IPv6 TClass */
+ pseudo_bit_t sl[0x00004]; /* InfiniBand Service Level (SL) */
+/* -------------- */
+ pseudo_bit_t rgid_127_96[0x00020]; /* Remote GID[127:96] */
+/* -------------- */
+ pseudo_bit_t rgid_95_64[0x00020]; /* Remote GID[95:64] */
+/* -------------- */
+ pseudo_bit_t rgid_63_32[0x00020]; /* Remote GID[63:32] */
+/* -------------- */
+ pseudo_bit_t rgid_31_0[0x00020]; /* Remote GID[31:0] */
+/* -------------- */
+};
+
+/* HCA Command Register (HCR) */
+
+struct arbelprm_hca_command_register_st { /* Little Endian */
+ pseudo_bit_t in_param_h[0x00020]; /* Input Parameter: parameter[63:32] or pointer[63:32] to input mailbox (see command description) */
+/* -------------- */
+ pseudo_bit_t in_param_l[0x00020]; /* Input Parameter: parameter[31:0] or pointer[31:0] to input mailbox (see command description) */
+/* -------------- */
+ pseudo_bit_t input_modifier[0x00020];/* Input Parameter Modifier */
+/* -------------- */
+ pseudo_bit_t out_param_h[0x00020]; /* Output Parameter: parameter[63:32] or pointer[63:32] to output mailbox (see command description) */
+/* -------------- */
+ pseudo_bit_t out_param_l[0x00020]; /* Output Parameter: parameter[31:0] or pointer[31:0] to output mailbox (see command description) */
+/* -------------- */
+ pseudo_bit_t reserved0[0x00010];
+ pseudo_bit_t token[0x00010]; /* Software assigned token to the command, to uniquely identify it. The token is returned to the software in the EQE reported. */
+/* -------------- */
+ pseudo_bit_t opcode[0x0000c]; /* Command opcode */
+ pseudo_bit_t opcode_modifier[0x00004];/* Opcode Modifier, see specific description for each command. */
+ pseudo_bit_t reserved1[0x00006];
+ pseudo_bit_t e[0x00001]; /* Event Request
+ 0 - Don't report event (software will poll the GO bit)
+ 1 - Report event to EQ when the command completes */
+ pseudo_bit_t go[0x00001]; /* Go (0=Software ownership for the HCR, 1=Hardware ownership for the HCR)
+ Software can write to the HCR only if Go bit is cleared.
+ Software must set the Go bit to trigger the HW to execute the command. Software must not write to this register value other than 1 for the Go bit. */
+ pseudo_bit_t status[0x00008]; /* Command execution status report. Valid only if command interface in under SW ownership (Go bit is cleared)
+ 0 - command completed without error. If different than zero, command execution completed with error. Syndrom encoding is depended on command executed and is defined for each command */
+/* -------------- */
+};
+
+/* CQ Doorbell */
+
+struct arbelprm_cq_cmd_doorbell_st { /* Little Endian */
+ pseudo_bit_t cqn[0x00018]; /* CQ number accessed */
+ pseudo_bit_t cmd[0x00003]; /* Command to be executed on CQ
+ 0x0 - Reserved
+ 0x1 - Request notification for next Solicited completion event. CQ_param specifies the current CQ Consumer Counter.
+ 0x2 - Request notification for next Solicited or Unsolicited completion event. CQ_param specifies the current CQ Consumer Counter.
+ 0x3 - Request notification for multiple completions (Arm-N). CQ_param specifies the value of the CQ Counter that when reached by HW (i.e. HW generates a CQE into this Counter) Event will be generated
+ Other - Reserved */
+ pseudo_bit_t reserved0[0x00001];
+ pseudo_bit_t cmd_sn[0x00002]; /* Command Sequence Number - This field should be incremented upon receiving completion notification of the respective CQ.
+ This transition is done by ringing Request notification for next Solicited, Request notification for next Solicited or Unsolicited
+ completion or Request notification for multiple completions doorbells after receiving completion notification.
+ This field is initialized to Zero */
+ pseudo_bit_t reserved1[0x00002];
+/* -------------- */
+ pseudo_bit_t cq_param[0x00020]; /* parameter to be used by CQ command */
+/* -------------- */
+};
+
+/* RD-send doorbell */
+
+struct arbelprm_rd_send_doorbell_st { /* Little Endian */
+ pseudo_bit_t reserved0[0x00008];
+ pseudo_bit_t een[0x00018]; /* End-to-end context number (reliable datagram)
+ Must be zero for Nop and Bind operations */
+/* -------------- */
+ pseudo_bit_t reserved1[0x00008];
+ pseudo_bit_t qpn[0x00018]; /* QP number this doorbell is rung on */
+/* -------------- */
+ struct arbelprm_send_doorbell_st send_doorbell;/* Send Parameters */
+/* -------------- */
+};
+
+/* Multicast Group Member QP */
+
+struct arbelprm_mgmqp_st { /* Little Endian */
+ pseudo_bit_t qpn_i[0x00018]; /* QPN_i: QP number which is a member in this multicast group. Valid only if Qi bit is set. Length of the QPN_i list is set in INIT_HCA */
+ pseudo_bit_t reserved0[0x00007];
+ pseudo_bit_t qi[0x00001]; /* Qi: QPN_i is valid */
+/* -------------- */
+};
+
+/* vsd */
+
+struct arbelprm_vsd_st { /* Little Endian */
+ pseudo_bit_t vsd_dw0[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw1[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw2[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw3[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw4[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw5[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw6[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw7[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw8[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw9[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw10[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw11[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw12[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw13[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw14[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw15[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw16[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw17[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw18[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw19[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw20[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw21[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw22[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw23[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw24[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw25[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw26[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw27[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw28[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw29[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw30[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw31[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw32[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw33[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw34[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw35[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw36[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw37[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw38[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw39[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw40[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw41[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw42[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw43[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw44[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw45[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw46[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw47[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw48[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw49[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw50[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw51[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw52[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw53[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw54[0x00020];
+/* -------------- */
+ pseudo_bit_t vsd_dw55[0x00020];
+/* -------------- */
+};
+
+/* ACCESS_LAM_inject_errors */
+
+struct arbelprm_access_lam_inject_errors_st { /* Little Endian */
+ struct arbelprm_access_lam_inject_errors_input_parameter_st access_lam_inject_errors_input_parameter;
+/* -------------- */
+ struct arbelprm_access_lam_inject_errors_input_modifier_st access_lam_inject_errors_input_modifier;
+/* -------------- */
+ pseudo_bit_t reserved0[0x00020];
+/* -------------- */
+};
+
+/* Logical DIMM Information */
+
+struct arbelprm_dimminfo_st { /* Little Endian */
+ pseudo_bit_t dimmsize[0x00010]; /* Size of DIMM in units of 2^20 Bytes. This value is valid only when DIMMStatus is 0. */
+ pseudo_bit_t reserved0[0x00008];
+ pseudo_bit_t dimmstatus[0x00001]; /* DIMM Status
+ 0 - Enabled
+ 1 - Disabled
+ */
+ pseudo_bit_t dh[0x00001]; /* When set, the DIMM is Hidden and can not be accessed from the PCI bus. */
+ pseudo_bit_t wo[0x00001]; /* When set, the DIMM is write only.
+ If data integrity is configured (other than none), the DIMM must be
+ only targeted by write transactions where the address and size are multiples of 16 bytes. */
+ pseudo_bit_t reserved1[0x00005];
+/* -------------- */
+ pseudo_bit_t spd[0x00001]; /* 0 - DIMM SPD was read from DIMM
+ 1 - DIMM SPD was read from InfiniHost-III-EX NVMEM */
+ pseudo_bit_t sladr[0x00003]; /* SPD Slave Address 3 LSBits.
+ Valid only if spd bit is 0. */
+ pseudo_bit_t sock_num[0x00002]; /* DIMM socket number (for double sided DIMM one of the two numbers will be reported) */
+ pseudo_bit_t syn[0x00004]; /* Error syndrome (valid regardless of status value)
+ 0 - DIMM has no error
+ 1 - SPD error (e.g. checksum error, no response, error while reading)
+ 2 - DIMM out of bounds (e.g. DIMM rows number is not between 7 and 14, DIMM type is not 2)
+ 3 - DIMM conflict (e.g. mix of registered and unbuffered DIMMs, CAS latency conflict)
+ 5 - DIMM size trimmed due to configuration (size exceeds)
+ other - Error, reserved
+ */
+ pseudo_bit_t reserved2[0x00016];
+/* -------------- */
+ pseudo_bit_t reserved3[0x00040];
+/* -------------- */
+ pseudo_bit_t dimm_start_adr_h[0x00020];/* DIMM memory start address [63:32]. This value is valid only when DIMMStatus is 0. */
+/* -------------- */
+ pseudo_bit_t dimm_start_adr_l[0x00020];/* DIMM memory start address [31:0]. This value is valid only when DIMMStatus is 0. */
+/* -------------- */
+ pseudo_bit_t reserved4[0x00040];
+/* -------------- */
+};
+
+/* UAR Parameters */
+
+struct arbelprm_uar_params_st { /* Little Endian */
+ pseudo_bit_t uar_base_addr_h[0x00020];/* UAR Base (pyhsical) Address [63:32] (QUERY_HCA only) */
+/* -------------- */
+ pseudo_bit_t reserved0[0x00014];
+ pseudo_bit_t uar_base_addr_l[0x0000c];/* UAR Base (pyhsical) Address [31:20] (QUERY_HCA only) */
+/* -------------- */
+ pseudo_bit_t uar_page_sz[0x00008]; /* This field defines the size of each UAR page.
+ Size of UAR Page is 4KB*2^UAR_Page_Size */
+ pseudo_bit_t log_max_uars[0x00004]; /* Number of UARs supported is 2^log_max_UARs */
+ pseudo_bit_t reserved1[0x00004];
+ pseudo_bit_t log_uar_entry_sz[0x00006];/* Size of UAR Context entry is 2^log_uar_sz in 4KByte pages */
+ pseudo_bit_t reserved2[0x0000a];
+/* -------------- */
+ pseudo_bit_t reserved3[0x00020];
+/* -------------- */
+ pseudo_bit_t uar_scratch_base_addr_h[0x00020];/* Base address of UAR scratchpad [63:32].
+ Number of entries in table is 2^log_max_uars.
+ Table must be aligned to its size */
+/* -------------- */
+ pseudo_bit_t uar_scratch_base_addr_l[0x00020];/* Base address of UAR scratchpad [31:0].
+ Number of entries in table is 2^log_max_uars.
+ Table must be aligned to its size. */
+/* -------------- */
+ pseudo_bit_t uar_context_base_addr_h[0x00020];/* Base address of UAR Context [63:32].
+ Number of entries in table is 2^log_max_uars.
+ Table must be aligned to its size. */
+/* -------------- */
+ pseudo_bit_t uar_context_base_addr_l[0x00020];/* Base address of UAR Context [31:0].
+ Number of entries in table is 2^log_max_uars.
+ Table must be aligned to its size. */
+/* -------------- */
+};
+
+/* Translation and Protection Tables Parameters */
+
+struct arbelprm_tptparams_st { /* Little Endian */
+ pseudo_bit_t mpt_base_adr_h[0x00020];/* MPT - Memory Protection Table base physical address [63:32].
+ Entry size is 64 bytes.
+ Table must be aligned to its size.
+ Address may be set to 0xFFFFFFFF if address translation and protection is not supported. */
+/* -------------- */
+ pseudo_bit_t mpt_base_adr_l[0x00020];/* MPT - Memory Protection Table base physical address [31:0].
+ Entry size is 64 bytes.
+ Table must be aligned to its size.
+ Address may be set to 0xFFFFFFFF if address translation and protection is not supported. */
+/* -------------- */
+ pseudo_bit_t log_mpt_sz[0x00006]; /* Log (base 2) of the number of region/windows entries in the MPT table. */
+ pseudo_bit_t reserved0[0x00002];
+ pseudo_bit_t pfto[0x00005]; /* Page Fault RNR Timeout -
+ The field returned in RNR Naks generated when a page fault is detected.
+ It has no effect when on-demand-paging is not used. */
+ pseudo_bit_t reserved1[0x00013];
+/* -------------- */
+ pseudo_bit_t reserved2[0x00020];
+/* -------------- */
+ pseudo_bit_t mtt_base_addr_h[0x00020];/* MTT - Memory Translation table base physical address [63:32].
+ Table must be aligned to its size.
+ Address may be set to 0xFFFFFFFF if address translation and protection is not supported. */
+/* -------------- */
+ pseudo_bit_t mtt_base_addr_l[0x00020];/* MTT - Memory Translation table base physical address [31:0].
+ Table must be aligned to its size.
+ Address may be set to 0xFFFFFFFF if address translation and protection is not supported. */
+/* -------------- */
+ pseudo_bit_t reserved3[0x00040];
+/* -------------- */
+};
+
+/* Multicast Support Parameters */
+
+struct arbelprm_multicastparam_st { /* Little Endian */
+ pseudo_bit_t mc_base_addr_h[0x00020];/* Base Address of the Multicast Table [63:32].
+ The base address must be aligned to the entry size.
+ Address may be set to 0xFFFFFFFF if multicast is not supported. */
+/* -------------- */
+ pseudo_bit_t mc_base_addr_l[0x00020];/* Base Address of the Multicast Table [31:0].
+ The base address must be aligned to the entry size.
+ Address may be set to 0xFFFFFFFF if multicast is not supported. */
+/* -------------- */
+ pseudo_bit_t reserved0[0x00040];
+/* -------------- */
+ pseudo_bit_t log_mc_table_entry_sz[0x00010];/* Log2 of the Size of multicast group member (MGM) entry.
+ Must be greater than 5 (to allow CTRL and GID sections).
+ That implies the number of QPs per MC table entry. */
+ pseudo_bit_t reserved1[0x00010];
+/* -------------- */
+ pseudo_bit_t mc_table_hash_sz[0x00011];/* Number of entries in multicast DGID hash table (must be power of 2)
+ INIT_HCA - the required number of entries
+ QUERY_HCA - the actual number of entries assigned by firmware (will be less than or equal to the amount required in INIT_HCA) */
+ pseudo_bit_t reserved2[0x0000f];
+/* -------------- */
+ pseudo_bit_t log_mc_table_sz[0x00005];/* Log2 of the overall number of MC entries in the MCG table (includes both hash and auxiliary tables) */
+ pseudo_bit_t reserved3[0x00013];
+ pseudo_bit_t mc_hash_fn[0x00003]; /* Multicast hash function
+ 0 - Default hash function
+ other - reserved */
+ pseudo_bit_t reserved4[0x00005];
+/* -------------- */
+ pseudo_bit_t reserved5[0x00020];
+/* -------------- */
+};
+
+/* QPC/EEC/CQC/EQC/RDB Parameters */
+
+struct arbelprm_qpcbaseaddr_st { /* Little Endian */
+ pseudo_bit_t reserved0[0x00080];
+/* -------------- */
+ pseudo_bit_t qpc_base_addr_h[0x00020];/* QPC Base Address [63:32]
+ Table must be aligned on its size */
+/* -------------- */
+ pseudo_bit_t log_num_of_qp[0x00005];/* Log base 2 of number of supported QPs */
+ pseudo_bit_t reserved1[0x00002];
+ pseudo_bit_t qpc_base_addr_l[0x00019];/* QPC Base Address [31:7]
+ Table must be aligned on its size */
+/* -------------- */
+ pseudo_bit_t reserved2[0x00040];
+/* -------------- */
+ pseudo_bit_t eec_base_addr_h[0x00020];/* EEC Base Address [63:32]
+ Table must be aligned on its size.
+ Address may be set to 0xFFFFFFFF if RD is not supported. */
+/* -------------- */
+ pseudo_bit_t log_num_of_ee[0x00005];/* Log base 2 of number of supported EEs. */
+ pseudo_bit_t reserved3[0x00002];
+ pseudo_bit_t eec_base_addr_l[0x00019];/* EEC Base Address [31:7]
+ Table must be aligned on its size
+ Address may be set to 0xFFFFFFFF if RD is not supported. */
+/* -------------- */
+ pseudo_bit_t srqc_base_addr_h[0x00020];/* SRQ Context Base Address [63:32]
+ Table must be aligned on its size
+ Address may be set to 0xFFFFFFFF if SRQ is not supported. */
+/* -------------- */
+ pseudo_bit_t log_num_of_srq[0x00005];/* Log base 2 of number of supported SRQs. */
+ pseudo_bit_t srqc_base_addr_l[0x0001b];/* SRQ Context Base Address [31:5]
+ Table must be aligned on its size
+ Address may be set to 0xFFFFFFFF if SRQ is not supported. */
+/* -------------- */
+ pseudo_bit_t cqc_base_addr_h[0x00020];/* CQC Base Address [63:32]
+ Table must be aligned on its size */
+/* -------------- */
+ pseudo_bit_t log_num_of_cq[0x00005];/* Log base 2 of number of supported CQs. */
+ pseudo_bit_t reserved4[0x00001];
+ pseudo_bit_t cqc_base_addr_l[0x0001a];/* CQC Base Address [31:6]
+ Table must be aligned on its size */
+/* -------------- */
+ pseudo_bit_t reserved5[0x00040];
+/* -------------- */
+ pseudo_bit_t eqpc_base_addr_h[0x00020];/* Extended QPC Base Address [63:32]
+ Table has same number of entries as QPC table.
+ Table must be aligned to entry size. */
+/* -------------- */
+ pseudo_bit_t eqpc_base_addr_l[0x00020];/* Extended QPC Base Address [31:0]
+ Table has same number of entries as QPC table.
+ Table must be aligned to entry size. */
+/* -------------- */
+ pseudo_bit_t reserved6[0x00040];
+/* -------------- */
+ pseudo_bit_t eeec_base_addr_h[0x00020];/* Extended EEC Base Address [63:32]
+ Table has same number of entries as EEC table.
+ Table must be aligned to entry size.
+ Address may be set to 0xFFFFFFFF if RD is not supported. */
+/* -------------- */
+ pseudo_bit_t eeec_base_addr_l[0x00020];/* Extended EEC Base Address [31:0]
+ Table has same number of entries as EEC table.
+ Table must be aligned to entry size.
+ Address may be set to 0xFFFFFFFF if RD is not supported. */
+/* -------------- */
+ pseudo_bit_t reserved7[0x00040];
+/* -------------- */
+ pseudo_bit_t eqc_base_addr_h[0x00020];/* EQC Base Address [63:32]
+ Address may be set to 0xFFFFFFFF if EQs are not supported.
+ Table must be aligned to entry size. */
+/* -------------- */
+ pseudo_bit_t log_num_eq[0x00004]; /* Log base 2 of number of supported EQs.
+ Must be 6 or less in InfiniHost-III-EX. */
+ pseudo_bit_t reserved8[0x00002];
+ pseudo_bit_t eqc_base_addr_l[0x0001a];/* EQC Base Address [31:6]
+ Address may be set to 0xFFFFFFFF if EQs are not supported.
+ Table must be aligned to entry size. */
+/* -------------- */
+ pseudo_bit_t reserved9[0x00040];
+/* -------------- */
+ pseudo_bit_t rdb_base_addr_h[0x00020];/* Base address of table that holds remote read and remote atomic requests [63:32].
+ Address may be set to 0xFFFFFFFF if remote RDMA reads are not supported.
+ Please refer to QP and EE chapter for further explanation on RDB allocation. */
+/* -------------- */
+ pseudo_bit_t rdb_base_addr_l[0x00020];/* Base address of table that holds remote read and remote atomic requests [31:0].
+ Table must be aligned to RDB entry size (32 bytes).
+ Address may be set to zero if remote RDMA reads are not supported.
+ Please refer to QP and EE chapter for further explanation on RDB allocation. */
+/* -------------- */
+ pseudo_bit_t reserved10[0x00040];
+/* -------------- */
+};
+
+/* Header_Log_Register */
+
+struct arbelprm_header_log_register_st { /* Little Endian */
+ pseudo_bit_t place_holder[0x00020];
+/* -------------- */
+ pseudo_bit_t reserved0[0x00060];
+/* -------------- */
+};
+
+/* Performance Monitors */
+
+struct arbelprm_performance_monitors_st { /* Little Endian */
+ pseudo_bit_t e0[0x00001]; /* Enables counting of respective performance counter */
+ pseudo_bit_t e1[0x00001]; /* Enables counting of respective performance counter */
+ pseudo_bit_t e2[0x00001]; /* Enables counting of respective performance counter */
+ pseudo_bit_t reserved0[0x00001];
+ pseudo_bit_t r0[0x00001]; /* If written to as '1 - resets respective performance counter, if written to az '0 - no change to matter */
+ pseudo_bit_t r1[0x00001]; /* If written to as '1 - resets respective performance counter, if written to az '0 - no change to matter */
+ pseudo_bit_t r2[0x00001]; /* If written to as '1 - resets respective performance counter, if written to az '0 - no change to matter */
+ pseudo_bit_t reserved1[0x00001];
+ pseudo_bit_t i0[0x00001]; /* Interrupt enable on respective counter overflow. '1 - interrupt enabled, '0 - interrupt disabled. */
+ pseudo_bit_t i1[0x00001]; /* Interrupt enable on respective counter overflow. '1 - interrupt enabled, '0 - interrupt disabled. */
+ pseudo_bit_t i2[0x00001]; /* Interrupt enable on respective counter overflow. '1 - interrupt enabled, '0 - interrupt disabled. */
+ pseudo_bit_t reserved2[0x00001];
+ pseudo_bit_t f0[0x00001]; /* Overflow flag. If set, overflow occurred on respective counter. Cleared if written to as '1 */
+ pseudo_bit_t f1[0x00001]; /* Overflow flag. If set, overflow occurred on respective counter. Cleared if written to as '1 */
+ pseudo_bit_t f2[0x00001]; /* Overflow flag. If set, overflow occurred on respective counter. Cleared if written to as '1 */
+ pseudo_bit_t reserved3[0x00001];
+ pseudo_bit_t ev_cnt1[0x00005]; /* Specifies event to be counted by Event_counter1 See XXX for events' definition. */
+ pseudo_bit_t reserved4[0x00003];
+ pseudo_bit_t ev_cnt2[0x00005]; /* Specifies event to be counted by Event_counter2 See XXX for events' definition. */
+ pseudo_bit_t reserved5[0x00003];
+/* -------------- */
+ pseudo_bit_t clock_counter[0x00020];
+/* -------------- */
+ pseudo_bit_t event_counter1[0x00020];
+/* -------------- */
+ pseudo_bit_t event_counter2[0x00020];/* Read/write event counter, counting events specified by EvCntl and EvCnt2 fields repsectively. When the event counter reaches is maximum value of 0xFFFFFF, the next event will cause it to roll over to zero, set F1 or F2 bit respectively and generate interrupt by I1 I2 bit respectively. */
+/* -------------- */
+};
+
+/* Receive segment format */
+
+struct arbelprm_wqe_segment_ctrl_recv_st { /* Little Endian */
+ struct arbelprm_recv_wqe_segment_next_st wqe_segment_next;
+/* -------------- */
+ pseudo_bit_t reserved0[0x00002];
+ pseudo_bit_t reserved1[0x00001];
+ pseudo_bit_t reserved2[0x00001];
+ pseudo_bit_t reserved3[0x0001c];
+/* -------------- */
+ pseudo_bit_t reserved4[0x00020];
+/* -------------- */
+};
+
+/* MLX WQE segment format */
+
+struct arbelprm_wqe_segment_ctrl_mlx_st { /* Little Endian */
+ pseudo_bit_t reserved0[0x00002];
+ pseudo_bit_t e[0x00001]; /* WQE event */
+ pseudo_bit_t c[0x00001]; /* Create CQE (for "requested signalling" QP) */
+ pseudo_bit_t icrc[0x00002]; /* icrc field detemines what to do with the last dword of the packet: 0 - Calculate ICRC and put it instead of last dword. Last dword must be 0x0. 1,2 - reserved. 3 - Leave last dword as is. Last dword must not be 0x0. */
+ pseudo_bit_t reserved1[0x00002];
+ pseudo_bit_t sl[0x00004];
+ pseudo_bit_t max_statrate[0x00004];
+ pseudo_bit_t slr[0x00001]; /* 0= take slid from port. 1= take slid from given headers */
+ pseudo_bit_t v15[0x00001]; /* Send packet over VL15 */
+ pseudo_bit_t reserved2[0x0000e];
+/* -------------- */
+ pseudo_bit_t vcrc[0x00010]; /* Packet's VCRC (if not 0 - otherwise computed by HW) */
+ pseudo_bit_t rlid[0x00010]; /* Destination LID (must match given headers) */
+/* -------------- */
+ pseudo_bit_t reserved3[0x00040];
+/* -------------- */
+};
+
+/* Send WQE segment format */
+
+struct arbelprm_send_wqe_segment_st { /* Little Endian */
+ struct arbelprm_wqe_segment_next_st wqe_segment_next;/* Send wqe segment next */
+/* -------------- */
+ struct arbelprm_wqe_segment_ctrl_send_st wqe_segment_ctrl_send;/* Send wqe segment ctrl */
+/* -------------- */
+ struct arbelprm_wqe_segment_rd_st wqe_segment_rd;/* Send wqe segment rd */
+/* -------------- */
+ struct arbelprm_wqe_segment_ud_st wqe_segment_ud;/* Send wqe segment ud */
+/* -------------- */
+ struct arbelprm_wqe_segment_bind_st wqe_segment_bind;/* Send wqe segment bind */
+/* -------------- */
+ pseudo_bit_t reserved0[0x00180];
+/* -------------- */
+ struct arbelprm_wqe_segment_remote_address_st wqe_segment_remote_address;/* Send wqe segment remote address */
+/* -------------- */
+ struct arbelprm_wqe_segment_atomic_st wqe_segment_atomic;/* Send wqe segment atomic */
+/* -------------- */
+ struct arbelprm_fast_registration_segment_st fast_registration_segment;/* Fast Registration Segment */
+/* -------------- */
+ struct arbelprm_local_invalidate_segment_st local_invalidate_segment;/* local invalidate segment */
+/* -------------- */
+ struct arbelprm_wqe_segment_data_ptr_st wqe_segment_data_ptr;/* Send wqe segment data ptr */
+/* -------------- */
+ struct arbelprm_wqe_segment_data_inline_st wqe_segment_data_inline;/* Send wqe segment data inline */
+/* -------------- */
+ pseudo_bit_t reserved1[0x00200];
+/* -------------- */
+};
+
+/* QP and EE Context Entry */
+
+struct arbelprm_queue_pair_ee_context_entry_st { /* Little Endian */
+ pseudo_bit_t reserved0[0x00008];
+ pseudo_bit_t de[0x00001]; /* Send/Receive Descriptor Event enable - if set, events can be generated upon descriptors' completion on send/receive queue (controlled by E bit in WQE). Invalid in EE context */
+ pseudo_bit_t reserved1[0x00002];
+ pseudo_bit_t pm_state[0x00002]; /* Path migration state (Migrated, Armed or Rearm)
+ 11-Migrated
+ 00-Armed
+ 01-Rearm
+ 10-Reserved
+ Should be set to 11 for UD QPs and for QPs which do not support APM */
+ pseudo_bit_t reserved2[0x00003];
+ pseudo_bit_t st[0x00003]; /* Service type (invalid in EE context):
+ 000-Reliable Connection
+ 001-Unreliable Connection
+ 010-Reliable Datagram
+ 011-Unreliable Datagram
+ 111-MLX transport (raw bits injection). Used for management QPs and RAW */
+ pseudo_bit_t reserved3[0x00009];
+ pseudo_bit_t state[0x00004]; /* QP/EE state:
+ 0 - RST
+ 1 - INIT
+ 2 - RTR
+ 3 - RTS
+ 4 - SQEr
+ 5 - SQD (Send Queue Drained)
+ 6 - ERR
+ 7 - Send Queue Draining
+ 8 - Reserved
+ 9 - Suspended
+ A- F - Reserved
+ (Valid for QUERY_QPEE and ERR2RST_QPEE commands only) */
+/* -------------- */
+ pseudo_bit_t reserved4[0x00020];
+/* -------------- */
+ pseudo_bit_t sched_queue[0x00004]; /* Schedule queue to be used for WQE scheduling to execution. Determines QOS for this QP. */
+ pseudo_bit_t rlky[0x00001]; /* When set this QP can use the Reserved L_Key */
+ pseudo_bit_t reserved5[0x00003];
+ pseudo_bit_t log_sq_stride[0x00003];/* Stride on the send queue. WQ entry is 16*(2^log_SQ_stride) bytes.
+ Stride must be equal or bigger then 64 bytes (minimum log_RQ_stride value allowed is 2). */
+ pseudo_bit_t log_sq_size[0x00004]; /* Log2 of the Number of WQEs in the Send Queue. */
+ pseudo_bit_t reserved6[0x00001];
+ pseudo_bit_t log_rq_stride[0x00003];/* Stride on the receive queue. WQ entry is 16*(2^log_RQ_stride) bytes.
+ Stride must be equal or bigger then 64 bytes (minimum log_RQ_stride value allowed is 2). */
+ pseudo_bit_t log_rq_size[0x00004]; /* Log2 of the Number of WQEs in the Receive Queue. */
+ pseudo_bit_t reserved7[0x00001];
+ pseudo_bit_t msg_max[0x00005]; /* Max message size allowed on the QP. Maximum message size is 2^msg_Max.
+ Must be equal to MTU for UD and MLX QPs. */
+ pseudo_bit_t mtu[0x00003]; /* MTU of the QP (Must be the same for both paths: primary and alternative):
+ 0x1 - 256 bytes
+ 0x2 - 512
+ 0x3 - 1024
+ 0x4 - 2048
+ other - reserved
+
+ Should be configured to 0x4 for UD and MLX QPs. */
+/* -------------- */
+ pseudo_bit_t usr_page[0x00018]; /* QP (see "non_privileged Access to the HCA Hardware"). Not valid (reserved) in EE context. */
+ pseudo_bit_t reserved8[0x00008];
+/* -------------- */
+ pseudo_bit_t local_qpn_een[0x00018];/* Local QP/EE number Lower bits determine position of this record in QPC table, and - thus - constrained
+ This field is valid for QUERY and ERR2RST commands only. */
+ pseudo_bit_t reserved9[0x00008];
+/* -------------- */
+ pseudo_bit_t remote_qpn_een[0x00018];/* Remote QP/EE number */
+ pseudo_bit_t reserved10[0x00008];
+/* -------------- */
+ pseudo_bit_t reserved11[0x00040];
+/* -------------- */
+ struct arbelprm_address_path_st primary_address_path;/* Primary address path for the QP/EE */
+/* -------------- */
+ struct arbelprm_address_path_st alternative_address_path;/* Alternate address path for the QP/EE */
+/* -------------- */
+ pseudo_bit_t rdd[0x00018]; /* Reliable Datagram Domain */
+ pseudo_bit_t reserved12[0x00008];
+/* -------------- */
+ pseudo_bit_t pd[0x00018]; /* QP protection domain. Not valid (reserved) in EE context. */
+ pseudo_bit_t reserved13[0x00008];
+/* -------------- */
+ pseudo_bit_t wqe_base_adr_h[0x00020];/* Bits 63:32 of WQE address for both SQ and RQ.
+ Reserved for EE context. */
+/* -------------- */
+ pseudo_bit_t wqe_lkey[0x00020]; /* memory key (L-Key) to be used to access WQEs. Not valid (reserved) in EE context. */
+/* -------------- */
+ pseudo_bit_t reserved14[0x00003];
+ pseudo_bit_t ssc[0x00001]; /* Send Signaled Completion
+ 1 - all send WQEs generate CQEs.
+ 0 - only send WQEs with C bit set generate completion.
+ Not valid (reserved) in EE context. */
+ pseudo_bit_t sic[0x00001]; /* If set - Ignore end to end credits on send queue. Not valid (reserved) in EE context. */
+ pseudo_bit_t cur_retry_cnt[0x00003];/* Current transport retry counter (QUERY_QPEE only).
+ The current transport retry counter can vary from retry_count down to 1, where 1 means that the last retry attempt is currently executing. */
+ pseudo_bit_t cur_rnr_retry[0x00003];/* Current RNR retry counter (QUERY_QPEE only).
+ The current RNR retry counter can vary from rnr_retry to 1, where 1 means that the last retry attempt is currently executing. */
+ pseudo_bit_t fre[0x00001]; /* Fast Registration Work Request Enabled. (Reserved for EE) */
+ pseudo_bit_t reserved15[0x00001];
+ pseudo_bit_t sae[0x00001]; /* If set - Atomic operations enabled on send queue. Not valid (reserved) in EE context. */
+ pseudo_bit_t swe[0x00001]; /* If set - RDMA - write enabled on send queue. Not valid (reserved) in EE context. */
+ pseudo_bit_t sre[0x00001]; /* If set - RDMA - read enabled on send queue. Not valid (reserved) in EE context. */
+ pseudo_bit_t retry_count[0x00003]; /* Transport timeout Retry count */
+ pseudo_bit_t reserved16[0x00002];
+ pseudo_bit_t sra_max[0x00003]; /* Maximum number of outstanding RDMA-read/Atomic operations allowed in the send queue. Maximum number is 2^SRA_Max. Must be zero in EE context. */
+ pseudo_bit_t flight_lim[0x00004]; /* Number of outstanding (in-flight) messages on the wire allowed for this send queue.
+ Number of outstanding messages is 2^Flight_Lim.
+ Use 0xF for unlimited number of outstanding messages. */
+ pseudo_bit_t ack_req_freq[0x00004]; /* ACK required frequency. ACK required bit will be set in every 2^AckReqFreq packets at least. Not valid for RD QP. */
+/* -------------- */
+ pseudo_bit_t reserved17[0x00020];
+/* -------------- */
+ pseudo_bit_t next_send_psn[0x00018];/* Next PSN to be sent */
+ pseudo_bit_t reserved18[0x00008];
+/* -------------- */
+ pseudo_bit_t cqn_snd[0x00018]; /* CQ number completions from the send queue to be reported to. Not valid (reserved) in EE context. */
+ pseudo_bit_t reserved19[0x00008];
+/* -------------- */
+ pseudo_bit_t reserved20[0x00006];
+ pseudo_bit_t snd_wqe_base_adr_l[0x0001a];/* While opening (creating) the WQ, this field should contain the address of first descriptor to be posted. Not valid (reserved) in EE context. */
+/* -------------- */
+ pseudo_bit_t snd_db_record_index[0x00020];/* Index in the UAR Context Table Entry.
+ HW uses this index as an offset from the UAR Context Table Entry in order to read this SQ doorbell record.
+ The entry is obtained via the usr_page field.
+ Not valid for EE. */
+/* -------------- */
+ pseudo_bit_t last_acked_psn[0x00018];/* The last acknowledged PSN for the requester (QUERY_QPEE only) */
+ pseudo_bit_t reserved21[0x00008];
+/* -------------- */
+ pseudo_bit_t ssn[0x00018]; /* Requester Send Sequence Number (QUERY_QPEE only) */
+ pseudo_bit_t reserved22[0x00008];
+/* -------------- */
+ pseudo_bit_t reserved23[0x00003];
+ pseudo_bit_t rsc[0x00001]; /* 1 - all receive WQEs generate CQEs.
+ 0 - only receive WQEs with C bit set generate completion.
+ Not valid (reserved) in EE context.
+ */
+ pseudo_bit_t ric[0x00001]; /* Invalid Credits.
+ 1 - place "Invalid Credits" to ACKs sent from this queue.
+ 0 - ACKs report the actual number of end to end credits on the connection.
+ Not valid (reserved) in EE context.
+ Must be set to 1 on QPs which are attached to SRQ. */
+ pseudo_bit_t reserved24[0x00008];
+ pseudo_bit_t rae[0x00001]; /* If set - Atomic operations enabled. on receive queue. Not valid (reserved) in EE context. */
+ pseudo_bit_t rwe[0x00001]; /* If set - RDMA - write enabled on receive queue. Not valid (reserved) in EE context. */
+ pseudo_bit_t rre[0x00001]; /* If set - RDMA - read enabled on receive queue. Not valid (reserved) in EE context. */
+ pseudo_bit_t reserved25[0x00005];
+ pseudo_bit_t rra_max[0x00003]; /* Maximum number of outstanding RDMA-read/Atomic operations allowed on receive queue is 2^RRA_Max.
+ Must be 0 for EE context. */
+ pseudo_bit_t reserved26[0x00008];
+/* -------------- */
+ pseudo_bit_t next_rcv_psn[0x00018]; /* Next (expected) PSN on receive */
+ pseudo_bit_t min_rnr_nak[0x00005]; /* Minimum RNR NAK timer value (TTTTT field encoding according to the IB spec Vol1 9.7.5.2.8).
+ Not valid (reserved) in EE context. */
+ pseudo_bit_t reserved27[0x00003];
+/* -------------- */
+ pseudo_bit_t reserved28[0x00005];
+ pseudo_bit_t ra_buff_indx[0x0001b]; /* Index to outstanding read/atomic buffer.
+ This field constructs the address to the RDB for maintaining the incoming RDMA read and atomic requests. */
+/* -------------- */
+ pseudo_bit_t cqn_rcv[0x00018]; /* CQ number completions from receive queue to be reported to. Not valid (reserved) in EE context. */
+ pseudo_bit_t reserved29[0x00008];
+/* -------------- */
+ pseudo_bit_t reserved30[0x00006];
+ pseudo_bit_t rcv_wqe_base_adr_l[0x0001a];/* While opening (creating) the WQ, this field should contain the address of first descriptor to be posted. Not valid (reserved) in EE context. */
+/* -------------- */
+ pseudo_bit_t rcv_db_record_index[0x00020];/* Index in the UAR Context Table Entry containing the doorbell record for the receive queue.
+ HW uses this index as an offset from the UAR Context Table Entry in order to read this RQ doorbell record.
+ The entry is obtained via the usr_page field.
+ Not valid for EE. */
+/* -------------- */
+ pseudo_bit_t q_key[0x00020]; /* Q_Key to be validated against received datagrams.
+ On send datagrams, if Q_Key[31] specified in the WQE is set, then this Q_Key will be transmitted in the outgoing message.
+ Not valid (reserved) in EE context. */
+/* -------------- */
+ pseudo_bit_t srqn[0x00018]; /* SRQN - Shared Receive Queue Number - specifies the SRQ number from which the QP dequeues receive descriptors.
+ SRQN is valid only if SRQ bit is set. Not valid (reserved) in EE context. */
+ pseudo_bit_t srq[0x00001]; /* SRQ - Shared Receive Queue. If this bit is set, then the QP is associated with a SRQ. Not valid (reserved) in EE context. */
+ pseudo_bit_t reserved31[0x00007];
+/* -------------- */
+ pseudo_bit_t rmsn[0x00018]; /* Responder current message sequence number (QUERY_QPEE only) */
+ pseudo_bit_t reserved32[0x00008];
+/* -------------- */
+ pseudo_bit_t sq_wqe_counter[0x00010];/* A 16bits counter that is incremented for each WQE posted to the SQ.
+ Must be 0x0 in SQ initialization.
+ (QUERY_QPEE only). */
+ pseudo_bit_t rq_wqe_counter[0x00010];/* A 16bits counter that is incremented for each WQE posted to the RQ.
+ Must be 0x0 in RQ initialization.
+ (QUERY_QPEE only). */
+/* -------------- */
+ pseudo_bit_t reserved33[0x00040];
+/* -------------- */
+};
+
+/* Clear Interrupt [63:0] */
+
+struct arbelprm_clr_int_st { /* Little Endian */
+ pseudo_bit_t clr_int_h[0x00020]; /* Clear Interrupt [63:32]
+ Write transactions to this register will clear (de-assert) the virtual interrupt output pins of InfiniHost-III-EX. The value to be written in this register is obtained by executing QUERY_ADAPTER command on command interface after system boot.
+ This register is write-only. Reading from this register will cause undefined result
+ */
+/* -------------- */
+ pseudo_bit_t clr_int_l[0x00020]; /* Clear Interrupt [31:0]
+ Write transactions to this register will clear (de-assert) the virtual interrupt output pins of InfiniHost-III-EX. The value to be written in this register is obtained by executing QUERY_ADAPTER command on command interface after system boot.
+ This register is write-only. Reading from this register will cause undefined result */
+/* -------------- */
+};
+
+/* EQ_Arm_DB_Region */
+
+struct arbelprm_eq_arm_db_region_st { /* Little Endian */
+ pseudo_bit_t eq_x_arm_h[0x00020]; /* EQ[63:32] X state.
+ This register is used to Arm EQs when setting the appropriate bits. */
+/* -------------- */
+ pseudo_bit_t eq_x_arm_l[0x00020]; /* EQ[31:0] X state.
+ This register is used to Arm EQs when setting the appropriate bits. */
+/* -------------- */
+};
+
+/* EQ Set CI DBs Table */
+
+struct arbelprm_eq_set_ci_table_st { /* Little Endian */
+ pseudo_bit_t eq0_set_ci[0x00020]; /* EQ0_Set_CI */
+/* -------------- */
+ pseudo_bit_t reserved0[0x00020];
+/* -------------- */
+ pseudo_bit_t eq1_set_ci[0x00020]; /* EQ1_Set_CI */
+/* -------------- */
+ pseudo_bit_t reserved1[0x00020];
+/* -------------- */
+ pseudo_bit_t eq2_set_ci[0x00020]; /* EQ2_Set_CI */
+/* -------------- */
+ pseudo_bit_t reserved2[0x00020];
+/* -------------- */
+ pseudo_bit_t eq3_set_ci[0x00020]; /* EQ3_Set_CI */
+/* -------------- */
+ pseudo_bit_t reserved3[0x00020];
+/* -------------- */
+ pseudo_bit_t eq4_set_ci[0x00020]; /* EQ4_Set_CI */
+/* -------------- */
+ pseudo_bit_t reserved4[0x00020];
+/* -------------- */
+ pseudo_bit_t eq5_set_ci[0x00020]; /* EQ5_Set_CI */
+/* -------------- */
+ pseudo_bit_t reserved5[0x00020];
+/* -------------- */
+ pseudo_bit_t eq6_set_ci[0x00020]; /* EQ6_Set_CI */
+/* -------------- */
+ pseudo_bit_t reserved6[0x00020];
+/* -------------- */
+ pseudo_bit_t eq7_set_ci[0x00020]; /* EQ7_Set_CI */
+/* -------------- */
+ pseudo_bit_t reserved7[0x00020];
+/* -------------- */
+ pseudo_bit_t eq8_set_ci[0x00020]; /* EQ8_Set_CI */
+/* -------------- */
+ pseudo_bit_t reserved8[0x00020];
+/* -------------- */
+ pseudo_bit_t eq9_set_ci[0x00020]; /* EQ9_Set_CI */
+/* -------------- */
+ pseudo_bit_t reserved9[0x00020];
+/* -------------- */
+ pseudo_bit_t eq10_set_ci[0x00020]; /* EQ10_Set_CI */
+/* -------------- */
+ pseudo_bit_t reserved10[0x00020];
+/* -------------- */
+ pseudo_bit_t eq11_set_ci[0x00020]; /* EQ11_Set_CI */
+/* -------------- */
+ pseudo_bit_t reserved11[0x00020];
+/* -------------- */
+ pseudo_bit_t eq12_set_ci[0x00020]; /* EQ12_Set_CI */
+/* -------------- */
+ pseudo_bit_t reserved12[0x00020];
+/* -------------- */
+ pseudo_bit_t eq13_set_ci[0x00020]; /* EQ13_Set_CI */
+/* -------------- */
+ pseudo_bit_t reserved13[0x00020];
+/* -------------- */
+ pseudo_bit_t eq14_set_ci[0x00020]; /* EQ14_Set_CI */
+/* -------------- */
+ pseudo_bit_t reserved14[0x00020];
+/* -------------- */
+ pseudo_bit_t eq15_set_ci[0x00020]; /* EQ15_Set_CI */
+/* -------------- */
+ pseudo_bit_t reserved15[0x00020];
+/* -------------- */
+ pseudo_bit_t eq16_set_ci[0x00020]; /* EQ16_Set_CI */
+/* -------------- */
+ pseudo_bit_t reserved16[0x00020];
+/* -------------- */
+ pseudo_bit_t eq17_set_ci[0x00020]; /* EQ17_Set_CI */
+/* -------------- */
+ pseudo_bit_t reserved17[0x00020];
+/* -------------- */
+ pseudo_bit_t eq18_set_ci[0x00020]; /* EQ18_Set_CI */
+/* -------------- */
+ pseudo_bit_t reserved18[0x00020];
+/* -------------- */
+ pseudo_bit_t eq19_set_ci[0x00020]; /* EQ19_Set_CI */
+/* -------------- */
+ pseudo_bit_t reserved19[0x00020];
+/* -------------- */
+ pseudo_bit_t eq20_set_ci[0x00020]; /* EQ20_Set_CI */
+/* -------------- */
+ pseudo_bit_t reserved20[0x00020];
+/* -------------- */
+ pseudo_bit_t eq21_set_ci[0x00020]; /* EQ21_Set_CI */
+/* -------------- */
+ pseudo_bit_t reserved21[0x00020];
+/* -------------- */
+ pseudo_bit_t eq22_set_ci[0x00020]; /* EQ22_Set_CI */
+/* -------------- */
+ pseudo_bit_t reserved22[0x00020];
+/* -------------- */
+ pseudo_bit_t eq23_set_ci[0x00020]; /* EQ23_Set_CI */
+/* -------------- */
+ pseudo_bit_t reserved23[0x00020];
+/* -------------- */
+ pseudo_bit_t eq24_set_ci[0x00020]; /* EQ24_Set_CI */
+/* -------------- */
+ pseudo_bit_t reserved24[0x00020];
+/* -------------- */
+ pseudo_bit_t eq25_set_ci[0x00020]; /* EQ25_Set_CI */
+/* -------------- */
+ pseudo_bit_t reserved25[0x00020];
+/* -------------- */
+ pseudo_bit_t eq26_set_ci[0x00020]; /* EQ26_Set_CI */
+/* -------------- */
+ pseudo_bit_t reserved26[0x00020];
+/* -------------- */
+ pseudo_bit_t eq27_set_ci[0x00020]; /* EQ27_Set_CI */
+/* -------------- */
+ pseudo_bit_t reserved27[0x00020];
+/* -------------- */
+ pseudo_bit_t eq28_set_ci[0x00020]; /* EQ28_Set_CI */
+/* -------------- */
+ pseudo_bit_t reserved28[0x00020];
+/* -------------- */
+ pseudo_bit_t eq29_set_ci[0x00020]; /* EQ29_Set_CI */
+/* -------------- */
+ pseudo_bit_t reserved29[0x00020];
+/* -------------- */
+ pseudo_bit_t eq30_set_ci[0x00020]; /* EQ30_Set_CI */
+/* -------------- */
+ pseudo_bit_t reserved30[0x00020];
+/* -------------- */
+ pseudo_bit_t eq31_set_ci[0x00020]; /* EQ31_Set_CI */
+/* -------------- */
+ pseudo_bit_t reserved31[0x00020];
+/* -------------- */
+ pseudo_bit_t eq32_set_ci[0x00020]; /* EQ32_Set_CI */
+/* -------------- */
+ pseudo_bit_t reserved32[0x00020];
+/* -------------- */
+ pseudo_bit_t eq33_set_ci[0x00020]; /* EQ33_Set_CI */
+/* -------------- */
+ pseudo_bit_t reserved33[0x00020];
+/* -------------- */
+ pseudo_bit_t eq34_set_ci[0x00020]; /* EQ34_Set_CI */
+/* -------------- */
+ pseudo_bit_t reserved34[0x00020];
+/* -------------- */
+ pseudo_bit_t eq35_set_ci[0x00020]; /* EQ35_Set_CI */
+/* -------------- */
+ pseudo_bit_t reserved35[0x00020];
+/* -------------- */
+ pseudo_bit_t eq36_set_ci[0x00020]; /* EQ36_Set_CI */
+/* -------------- */
+ pseudo_bit_t reserved36[0x00020];
+/* -------------- */
+ pseudo_bit_t eq37_set_ci[0x00020]; /* EQ37_Set_CI */
+/* -------------- */
+ pseudo_bit_t reserved37[0x00020];
+/* -------------- */
+ pseudo_bit_t eq38_set_ci[0x00020]; /* EQ38_Set_CI */
+/* -------------- */
+ pseudo_bit_t reserved38[0x00020];
+/* -------------- */
+ pseudo_bit_t eq39_set_ci[0x00020]; /* EQ39_Set_CI */
+/* -------------- */
+ pseudo_bit_t reserved39[0x00020];
+/* -------------- */
+ pseudo_bit_t eq40_set_ci[0x00020]; /* EQ40_Set_CI */
+/* -------------- */
+ pseudo_bit_t reserved40[0x00020];
+/* -------------- */
+ pseudo_bit_t eq41_set_ci[0x00020]; /* EQ41_Set_CI */
+/* -------------- */
+ pseudo_bit_t reserved41[0x00020];
+/* -------------- */
+ pseudo_bit_t eq42_set_ci[0x00020]; /* EQ42_Set_CI */
+/* -------------- */
+ pseudo_bit_t reserved42[0x00020];
+/* -------------- */
+ pseudo_bit_t eq43_set_ci[0x00020]; /* EQ43_Set_CI */
+/* -------------- */
+ pseudo_bit_t reserved43[0x00020];
+/* -------------- */
+ pseudo_bit_t eq44_set_ci[0x00020]; /* EQ44_Set_CI */
+/* -------------- */
+ pseudo_bit_t reserved44[0x00020];
+/* -------------- */
+ pseudo_bit_t eq45_set_ci[0x00020]; /* EQ45_Set_CI */
+/* -------------- */
+ pseudo_bit_t reserved45[0x00020];
+/* -------------- */
+ pseudo_bit_t eq46_set_ci[0x00020]; /* EQ46_Set_CI */
+/* -------------- */
+ pseudo_bit_t reserved46[0x00020];
+/* -------------- */
+ pseudo_bit_t eq47_set_ci[0x00020]; /* EQ47_Set_CI */
+/* -------------- */
+ pseudo_bit_t reserved47[0x00020];
+/* -------------- */
+ pseudo_bit_t eq48_set_ci[0x00020]; /* EQ48_Set_CI */
+/* -------------- */
+ pseudo_bit_t reserved48[0x00020];
+/* -------------- */
+ pseudo_bit_t eq49_set_ci[0x00020]; /* EQ49_Set_CI */
+/* -------------- */
+ pseudo_bit_t reserved49[0x00020];
+/* -------------- */
+ pseudo_bit_t eq50_set_ci[0x00020]; /* EQ50_Set_CI */
+/* -------------- */
+ pseudo_bit_t reserved50[0x00020];
+/* -------------- */
+ pseudo_bit_t eq51_set_ci[0x00020]; /* EQ51_Set_CI */
+/* -------------- */
+ pseudo_bit_t reserved51[0x00020];
+/* -------------- */
+ pseudo_bit_t eq52_set_ci[0x00020]; /* EQ52_Set_CI */
+/* -------------- */
+ pseudo_bit_t reserved52[0x00020];
+/* -------------- */
+ pseudo_bit_t eq53_set_ci[0x00020]; /* EQ53_Set_CI */
+/* -------------- */
+ pseudo_bit_t reserved53[0x00020];
+/* -------------- */
+ pseudo_bit_t eq54_set_ci[0x00020]; /* EQ54_Set_CI */
+/* -------------- */
+ pseudo_bit_t reserved54[0x00020];
+/* -------------- */
+ pseudo_bit_t eq55_set_ci[0x00020]; /* EQ55_Set_CI */
+/* -------------- */
+ pseudo_bit_t reserved55[0x00020];
+/* -------------- */
+ pseudo_bit_t eq56_set_ci[0x00020]; /* EQ56_Set_CI */
+/* -------------- */
+ pseudo_bit_t reserved56[0x00020];
+/* -------------- */
+ pseudo_bit_t eq57_set_ci[0x00020]; /* EQ57_Set_CI */
+/* -------------- */
+ pseudo_bit_t reserved57[0x00020];
+/* -------------- */
+ pseudo_bit_t eq58_set_ci[0x00020]; /* EQ58_Set_CI */
+/* -------------- */
+ pseudo_bit_t reserved58[0x00020];
+/* -------------- */
+ pseudo_bit_t eq59_set_ci[0x00020]; /* EQ59_Set_CI */
+/* -------------- */
+ pseudo_bit_t reserved59[0x00020];
+/* -------------- */
+ pseudo_bit_t eq60_set_ci[0x00020]; /* EQ60_Set_CI */
+/* -------------- */
+ pseudo_bit_t reserved60[0x00020];
+/* -------------- */
+ pseudo_bit_t eq61_set_ci[0x00020]; /* EQ61_Set_CI */
+/* -------------- */
+ pseudo_bit_t reserved61[0x00020];
+/* -------------- */
+ pseudo_bit_t eq62_set_ci[0x00020]; /* EQ62_Set_CI */
+/* -------------- */
+ pseudo_bit_t reserved62[0x00020];
+/* -------------- */
+ pseudo_bit_t eq63_set_ci[0x00020]; /* EQ63_Set_CI */
+/* -------------- */
+ pseudo_bit_t reserved63[0x00020];
+/* -------------- */
+};
+
+/* InfiniHost-III-EX Configuration Registers */
+
+struct arbelprm_configuration_registers_st { /* Little Endian */
+ pseudo_bit_t reserved0[0x403400];
+/* -------------- */
+ struct arbelprm_hca_command_register_st hca_command_interface_register;/* HCA Command Register */
+/* -------------- */
+ pseudo_bit_t reserved1[0x3fcb20];
+/* -------------- */
+};
+
+/* QP_DB_Record */
+
+struct arbelprm_qp_db_record_st { /* Little Endian */
+ pseudo_bit_t counter[0x00010]; /* Modulo-64K counter of WQEs posted to the QP since its creation. Should be initialized to zero. */
+ pseudo_bit_t reserved0[0x00010];
+/* -------------- */
+ pseudo_bit_t reserved1[0x00005];
+ pseudo_bit_t res[0x00003]; /* 0x3 for SQ
+ 0x4 for RQ
+ 0x5 for SRQ */
+ pseudo_bit_t qp_number[0x00018]; /* QP number */
+/* -------------- */
+};
+
+/* CQ_ARM_DB_Record */
+
+struct arbelprm_cq_arm_db_record_st { /* Little Endian */
+ pseudo_bit_t counter[0x00020]; /* CQ counter for the arming request */
+/* -------------- */
+ pseudo_bit_t cmd[0x00003]; /* 0x0 - No command
+ 0x1 - Request notification for next Solicited completion event. Counter filed specifies the current CQ Consumer Counter.
+ 0x2 - Request notification for next Solicited or Unsolicited completion event. Counter filed specifies the current CQ Consumer counter.
+ 0x3 - Request notification for multiple completions (Arm-N). Counter filed specifies the value of the CQ Index that when reached by HW (i.e. HW generates a CQE into this Index) Event will be generated
+ Other - Reserved */
+ pseudo_bit_t cmd_sn[0x00002]; /* Command Sequence Number - See Table 35, "CQ Doorbell Layout" for definition of this filed */
+ pseudo_bit_t res[0x00003]; /* Must be 0x2 */
+ pseudo_bit_t cq_number[0x00018]; /* CQ number */
+/* -------------- */
+};
+
+/* CQ_CI_DB_Record */
+
+struct arbelprm_cq_ci_db_record_st { /* Little Endian */
+ pseudo_bit_t counter[0x00020]; /* CQ counter */
+/* -------------- */
+ pseudo_bit_t reserved0[0x00005];
+ pseudo_bit_t res[0x00003]; /* Must be 0x1 */
+ pseudo_bit_t cq_number[0x00018]; /* CQ number */
+/* -------------- */
+};
+
+/* Virtual_Physical_Mapping */
+
+struct arbelprm_virtual_physical_mapping_st { /* Little Endian */
+ pseudo_bit_t va_h[0x00020]; /* Virtual Address[63:32]. Valid only for MAP_ICM command. */
+/* -------------- */
+ pseudo_bit_t reserved0[0x0000c];
+ pseudo_bit_t va_l[0x00014]; /* Virtual Address[31:12]. Valid only for MAP_ICM command. */
+/* -------------- */
+ pseudo_bit_t pa_h[0x00020]; /* Physical Address[63:32] */
+/* -------------- */
+ pseudo_bit_t log2size[0x00006]; /* Log2 of the size in 4KB pages of the physical and virtual contiguous memory that starts at PA_L/H and VA_L/H */
+ pseudo_bit_t reserved1[0x00006];
+ pseudo_bit_t pa_l[0x00014]; /* Physical Address[31:12] */
+/* -------------- */
+};
+
+/* MOD_STAT_CFG */
+
+struct arbelprm_mod_stat_cfg_st { /* Little Endian */
+ pseudo_bit_t log_max_srqs[0x00005]; /* Log (base 2) of the number of SRQs to allocate (0 if no SRQs are required), valid only if srq bit is set. */
+ pseudo_bit_t reserved0[0x00001];
+ pseudo_bit_t srq[0x00001]; /* When set SRQs are supported */
+ pseudo_bit_t srq_m[0x00001]; /* Modify SRQ parameters */
+ pseudo_bit_t reserved1[0x00018];
+/* -------------- */
+ pseudo_bit_t reserved2[0x007e0];
+/* -------------- */
+};
+
+/* SRQ Context */
+
+struct arbelprm_srq_context_st { /* Little Endian */
+ pseudo_bit_t srqn[0x00018]; /* SRQ number */
+ pseudo_bit_t log_srq_size[0x00004]; /* Log2 of the Number of WQEs in the Receive Queue.
+ Maximum value is 0x10, i.e. 16M WQEs. */
+ pseudo_bit_t state[0x00004]; /* SRQ State:
+ 1111 - SW Ownership
+ 0000 - HW Ownership
+ 0001 - Error
+ Valid only on QUERY_SRQ and HW2SW_SRQ commands. */
+/* -------------- */
+ pseudo_bit_t l_key[0x00020]; /* memory key (L-Key) to be used to access WQEs. */
+/* -------------- */
+ pseudo_bit_t srq_db_record_index[0x00020];/* Index in the UAR Context Table Entry containing the doorbell record for the receive queue.
+ HW uses this index as an offset from the UAR Context Table Entry in order to read this SRQ doorbell record.
+ The entry is obtained via the usr_page field. */
+/* -------------- */
+ pseudo_bit_t usr_page[0x00018]; /* Index (offset) of user page allocated for this SRQ (see "non_privileged Access to the HCA Hardware"). Not valid (reserved) in EE context. */
+ pseudo_bit_t reserved0[0x00005];
+ pseudo_bit_t log_rq_stride[0x00003];/* Stride (max WQE size) on the receive queue. WQ entry is 16*(2^log_RQ_stride) bytes. */
+/* -------------- */
+ pseudo_bit_t wqe_addr_h[0x00020]; /* Bits 63:32 of WQE address (WQE base address) */
+/* -------------- */
+ pseudo_bit_t reserved1[0x00006];
+ pseudo_bit_t srq_wqe_base_adr_l[0x0001a];/* While opening (creating) the SRQ, this field should contain the address of first descriptor to be posted. */
+/* -------------- */
+ pseudo_bit_t pd[0x00018]; /* SRQ protection domain. */
+ pseudo_bit_t reserved2[0x00008];
+/* -------------- */
+ pseudo_bit_t wqe_cnt[0x00010]; /* WQE count on the SRQ.
+ Valid only on QUERY_SRQ and HW2SW_SRQ commands. */
+ pseudo_bit_t lwm[0x00010]; /* Limit Water Mark - if the LWM is not zero, and the wqe_cnt drops below LWM when a WQE is dequeued from the SRQ, then a SRQ limit event is fired and the LWM is set to zero. */
+/* -------------- */
+ pseudo_bit_t srq_wqe_counter[0x00010];/* A 16bits counter that is incremented for each WQE posted to the SQ.
+ Must be 0x0 in SRQ initialization.
+ (QUERY_SRQ only). */
+ pseudo_bit_t reserved3[0x00010];
+/* -------------- */
+ pseudo_bit_t reserved4[0x00060];
+/* -------------- */
+};
+
+/* PBL */
+
+struct arbelprm_pbl_st { /* Little Endian */
+ pseudo_bit_t mtt_0_h[0x00020]; /* First MTT[63:32] */
+/* -------------- */
+ pseudo_bit_t mtt_0_l[0x00020]; /* First MTT[31:0] */
+/* -------------- */
+ pseudo_bit_t mtt_1_h[0x00020]; /* Second MTT[63:32] */
+/* -------------- */
+ pseudo_bit_t mtt_1_l[0x00020]; /* Second MTT[31:0] */
+/* -------------- */
+ pseudo_bit_t mtt_2_h[0x00020]; /* Third MTT[63:32] */
+/* -------------- */
+ pseudo_bit_t mtt_2_l[0x00020]; /* Third MTT[31:0] */
+/* -------------- */
+ pseudo_bit_t mtt_3_h[0x00020]; /* Fourth MTT[63:32] */
+/* -------------- */
+ pseudo_bit_t mtt_3_l[0x00020]; /* Fourth MTT[31:0] */
+/* -------------- */
+};
+
+/* Performance Counters */
+
+struct arbelprm_performance_counters_st { /* Little Endian */
+ pseudo_bit_t sqpc_access_cnt[0x00020];/* SQPC cache access count */
+/* -------------- */
+ pseudo_bit_t sqpc_miss_cnt[0x00020];/* SQPC cache miss count */
+/* -------------- */
+ pseudo_bit_t reserved0[0x00040];
+/* -------------- */
+ pseudo_bit_t rqpc_access_cnt[0x00020];/* RQPC cache access count */
+/* -------------- */
+ pseudo_bit_t rqpc_miss_cnt[0x00020];/* RQPC cache miss count */
+/* -------------- */
+ pseudo_bit_t reserved1[0x00040];
+/* -------------- */
+ pseudo_bit_t cqc_access_cnt[0x00020];/* CQC cache access count */
+/* -------------- */
+ pseudo_bit_t cqc_miss_cnt[0x00020]; /* CQC cache miss count */
+/* -------------- */
+ pseudo_bit_t reserved2[0x00040];
+/* -------------- */
+ pseudo_bit_t tpt_access_cnt[0x00020];/* TPT cache access count */
+/* -------------- */
+ pseudo_bit_t mpt_miss_cnt[0x00020]; /* MPT cache miss count */
+/* -------------- */
+ pseudo_bit_t mtt_miss_cnt[0x00020]; /* MTT cache miss count */
+/* -------------- */
+ pseudo_bit_t reserved3[0x00620];
+/* -------------- */
+};
+
+/* Transport and CI Error Counters */
+
+struct arbelprm_transport_and_ci_error_counters_st { /* Little Endian */
+ pseudo_bit_t rq_num_lle[0x00020]; /* Responder - number of local length errors */
+/* -------------- */
+ pseudo_bit_t sq_num_lle[0x00020]; /* Requester - number of local length errors */
+/* -------------- */
+ pseudo_bit_t rq_num_lqpoe[0x00020]; /* Responder - number local QP operation error */
+/* -------------- */
+ pseudo_bit_t sq_num_lqpoe[0x00020]; /* Requester - number local QP operation error */
+/* -------------- */
+ pseudo_bit_t rq_num_leeoe[0x00020]; /* Responder - number local EE operation error */
+/* -------------- */
+ pseudo_bit_t sq_num_leeoe[0x00020]; /* Requester - number local EE operation error */
+/* -------------- */
+ pseudo_bit_t rq_num_lpe[0x00020]; /* Responder - number of local protection errors */
+/* -------------- */
+ pseudo_bit_t sq_num_lpe[0x00020]; /* Requester - number of local protection errors */
+/* -------------- */
+ pseudo_bit_t rq_num_wrfe[0x00020]; /* Responder - number of CQEs with error.
+ Incremented each time a CQE with error is generated */
+/* -------------- */
+ pseudo_bit_t sq_num_wrfe[0x00020]; /* Requester - number of CQEs with error.
+ Incremented each time a CQE with error is generated */
+/* -------------- */
+ pseudo_bit_t reserved0[0x00020];
+/* -------------- */
+ pseudo_bit_t sq_num_mwbe[0x00020]; /* Requester - number of memory window bind errors */
+/* -------------- */
+ pseudo_bit_t reserved1[0x00020];
+/* -------------- */
+ pseudo_bit_t sq_num_bre[0x00020]; /* Requester - number of bad response errors */
+/* -------------- */
+ pseudo_bit_t rq_num_lae[0x00020]; /* Responder - number of local access errors */
+/* -------------- */
+ pseudo_bit_t reserved2[0x00040];
+/* -------------- */
+ pseudo_bit_t sq_num_rire[0x00020]; /* Requester - number of remote invalid request errors
+ NAK-Invalid Request on:
+ 1. Unsupported OpCode: Responder detected an unsupported OpCode.
+ 2. Unexpected OpCode: Responder detected an error in the sequence of OpCodes, such
+ as a missing "Last" packet.
+ Note: there is no PSN error, thus this does not indicate a dropped packet. */
+/* -------------- */
+ pseudo_bit_t rq_num_rire[0x00020]; /* Responder - number of remote invalid request errors.
+ NAK may or may not be sent.
+ 1. QP Async Affiliated Error: Unsupported or Reserved OpCode (RC,RD only):
+ Inbound request OpCode was either reserved, or was for a function not supported by this
+ QP. (E.g. RDMA or ATOMIC on QP not set up for this).
+ 2. Misaligned ATOMIC: VA does not point to an aligned address on an atomic opera-tion.
+ 3. Too many RDMA READ or ATOMIC Requests: There were more requests received
+ and not ACKed than allowed for the connection.
+ 4. Out of Sequence OpCode, current packet is "First" or "Only": The Responder
+ detected an error in the sequence of OpCodes; a missing "Last" packet
+ 5. Out of Sequence OpCode, current packet is not "First" or "Only": The Responder
+ detected an error in the sequence of OpCodes; a missing "First" packet
+ 6. Local Length Error: Inbound "Send" request message exceeded the responder.s avail-able
+ buffer space.
+ 7. Length error: RDMA WRITE request message contained too much or too little pay-load
+ data compared to the DMA length advertised in the first or only packet.
+ 8. Length error: Payload length was not consistent with the opcode:
+ a: 0 byte <= "only" <= PMTU bytes
+ b: ("first" or "middle") == PMTU bytes
+ c: 1byte <= "last" <= PMTU bytes
+ 9. Length error: Inbound message exceeded the size supported by the CA port. */
+/* -------------- */
+ pseudo_bit_t sq_num_rae[0x00020]; /* Requester - number of remote access errors.
+ NAK-Remote Access Error on:
+ R_Key Violation: Responder detected an invalid R_Key while executing an RDMA
+ Request. */
+/* -------------- */
+ pseudo_bit_t rq_num_rae[0x00020]; /* Responder - number of remote access errors.
+ R_Key Violation Responder detected an R_Key violation while executing an RDMA
+ request.
+ NAK may or may not be sent. */
+/* -------------- */
+ pseudo_bit_t sq_num_roe[0x00020]; /* Requester - number of remote operation errors.
+ NAK-Remote Operation Error on:
+ Remote Operation Error: Responder encountered an error, (local to the responder),
+ which prevented it from completing the request. */
+/* -------------- */
+ pseudo_bit_t rq_num_roe[0x00020]; /* Responder - number of remote operation errors.
+ NAK-Remote Operation Error on:
+ 1. Malformed WQE: Responder detected a malformed Receive Queue WQE while pro-cessing
+ the packet.
+ 2. Remote Operation Error: Responder encountered an error, (local to the responder),
+ which prevented it from completing the request. */
+/* -------------- */
+ pseudo_bit_t sq_num_tree[0x00020]; /* Requester - number of transport retries exceeded errors */
+/* -------------- */
+ pseudo_bit_t reserved3[0x00020];
+/* -------------- */
+ pseudo_bit_t sq_num_rree[0x00020]; /* Requester - number of RNR nak retries exceeded errors */
+/* -------------- */
+ pseudo_bit_t reserved4[0x00020];
+/* -------------- */
+ pseudo_bit_t sq_num_lrdve[0x00020]; /* Requester - number of local RDD violation errors */
+/* -------------- */
+ pseudo_bit_t rq_num_rirdre[0x00020];/* Responder - number of remote invalid RD request errors */
+/* -------------- */
+ pseudo_bit_t reserved5[0x00040];
+/* -------------- */
+ pseudo_bit_t sq_num_rabrte[0x00020];/* Requester - number of remote aborted errors */
+/* -------------- */
+ pseudo_bit_t reserved6[0x00020];
+/* -------------- */
+ pseudo_bit_t sq_num_ieecne[0x00020];/* Requester - number of invalid EE context number errors */
+/* -------------- */
+ pseudo_bit_t reserved7[0x00020];
+/* -------------- */
+ pseudo_bit_t sq_num_ieecse[0x00020];/* Requester - invalid EE context state errors */
+/* -------------- */
+ pseudo_bit_t reserved8[0x00380];
+/* -------------- */
+ pseudo_bit_t rq_num_oos[0x00020]; /* Responder - number of out of sequence requests received */
+/* -------------- */
+ pseudo_bit_t sq_num_oos[0x00020]; /* Requester - number of out of sequence Naks received */
+/* -------------- */
+ pseudo_bit_t rq_num_mce[0x00020]; /* Responder - number of bad multicast packets received */
+/* -------------- */
+ pseudo_bit_t reserved9[0x00020];
+/* -------------- */
+ pseudo_bit_t rq_num_rsync[0x00020]; /* Responder - number of RESYNC operations */
+/* -------------- */
+ pseudo_bit_t sq_num_rsync[0x00020]; /* Requester - number of RESYNC operations */
+/* -------------- */
+ pseudo_bit_t rq_num_udsdprd[0x00020];/* The number of UD packets silently discarded on the receive queue due to lack of receive descriptor. */
+/* -------------- */
+ pseudo_bit_t reserved10[0x00020];
+/* -------------- */
+ pseudo_bit_t rq_num_ucsdprd[0x00020];/* The number of UC packets silently discarded on the receive queue due to lack of receive descriptor. */
+/* -------------- */
+ pseudo_bit_t reserved11[0x003e0];
+/* -------------- */
+ pseudo_bit_t num_cqovf[0x00020]; /* Number of CQ overflows */
+/* -------------- */
+ pseudo_bit_t num_eqovf[0x00020]; /* Number of EQ overflows */
+/* -------------- */
+ pseudo_bit_t num_baddb[0x00020]; /* Number of bad doorbells */
+/* -------------- */
+ pseudo_bit_t reserved12[0x002a0];
+/* -------------- */
+};
+
+/* Event_data Field - HCR Completion Event */
+
+struct arbelprm_hcr_completion_event_st { /* Little Endian */
+ pseudo_bit_t token[0x00010]; /* HCR Token */
+ pseudo_bit_t reserved0[0x00010];
+/* -------------- */
+ pseudo_bit_t reserved1[0x00020];
+/* -------------- */
+ pseudo_bit_t status[0x00008]; /* HCR Status */
+ pseudo_bit_t reserved2[0x00018];
+/* -------------- */
+ pseudo_bit_t out_param_h[0x00020]; /* HCR Output Parameter [63:32] */
+/* -------------- */
+ pseudo_bit_t out_param_l[0x00020]; /* HCR Output Parameter [31:0] */
+/* -------------- */
+ pseudo_bit_t reserved3[0x00020];
+/* -------------- */
+};
+
+/* Completion with Error CQE */
+
+struct arbelprm_completion_with_error_st { /* Little Endian */
+ pseudo_bit_t myqpn[0x00018]; /* Indicates the QP for which completion is being reported */
+ pseudo_bit_t reserved0[0x00008];
+/* -------------- */
+ pseudo_bit_t reserved1[0x00060];
+/* -------------- */
+ pseudo_bit_t reserved2[0x00010];
+ pseudo_bit_t vendor_code[0x00008];
+ pseudo_bit_t syndrome[0x00008]; /* Completion with error syndrome:
+ 0x01 - Local Length Error
+ 0x02 - Local QP Operation Error
+ 0x03 - Local EE Context Operation Error
+ 0x04 - Local Protection Error
+ 0x05 - Work Request Flushed Error
+ 0x06 - Memory Window Bind Error
+ 0x10 - Bad Response Error
+ 0x11 - Local Access Error
+ 0x12 - Remote Invalid Request Error
+ 0x13 - Remote Access Error
+ 0x14 - Remote Operation Error
+ 0x15 - Transport Retry Counter Exceeded
+ 0x16 - RNR Retry Counter Exceeded
+ 0x20 - Local RDD Violation Error
+ 0x21 - Remote Invalid RD Request
+ 0x22 - Remote Aborted Error
+ 0x23 - Invalid EE Context Number
+ 0x24 - Invalid EE Context State
+ other - Reserved
+ Syndrome is defined according to the IB specification volume 1. For detailed explanation of the syndromes, refer to chapters 10-11 of the IB specification rev 1.1. */
+/* -------------- */
+ pseudo_bit_t reserved3[0x00020];
+/* -------------- */
+ pseudo_bit_t reserved4[0x00006];
+ pseudo_bit_t wqe_addr[0x0001a]; /* Bits 31:6 of WQE virtual address completion is reported for. The 6 least significant bits are zero. */
+/* -------------- */
+ pseudo_bit_t reserved5[0x00007];
+ pseudo_bit_t owner[0x00001]; /* Owner field. Zero value of this field means SW ownership of CQE. */
+ pseudo_bit_t reserved6[0x00010];
+ pseudo_bit_t opcode[0x00008]; /* The opcode of WQE completion is reported for.
+
+ The following values are reported in case of completion with error:
+ 0xFE - For completion with error on Receive Queues
+ 0xFF - For completion with error on Send Queues */
+/* -------------- */
+};
+
+/* Resize CQ Input Mailbox */
+
+struct arbelprm_resize_cq_st { /* Little Endian */
+ pseudo_bit_t reserved0[0x00020];
+/* -------------- */
+ pseudo_bit_t start_addr_h[0x00020]; /* Start address of CQ[63:32].
+ Must be aligned on CQE size (32 bytes) */
+/* -------------- */
+ pseudo_bit_t start_addr_l[0x00020]; /* Start address of CQ[31:0].
+ Must be aligned on CQE size (32 bytes) */
+/* -------------- */
+ pseudo_bit_t reserved1[0x00018];
+ pseudo_bit_t log_cq_size[0x00005]; /* Log (base 2) of the CQ size (in entries) */
+ pseudo_bit_t reserved2[0x00003];
+/* -------------- */
+ pseudo_bit_t reserved3[0x00060];
+/* -------------- */
+ pseudo_bit_t l_key[0x00020]; /* Memory key (L_Key) to be used to access CQ */
+/* -------------- */
+ pseudo_bit_t reserved4[0x00100];
+/* -------------- */
+};
+
+/* MAD_IFC Input Modifier */
+
+struct arbelprm_mad_ifc_input_modifier_st { /* Little Endian */
+ pseudo_bit_t port_number[0x00008]; /* The packet reception port number (1 or 2). */
+ pseudo_bit_t mad_extended_info[0x00001];/* Mad_Extended_Info valid bit (MAD_IFC Input Mailbox data from offset 00100h and down). MAD_Extended_Info is read only if this bit is set.
+ Required for trap generation when BKey check is enabled and for global routed packets. */
+ pseudo_bit_t reserved0[0x00007];
+ pseudo_bit_t rlid[0x00010]; /* Remote (source) LID from the received MAD.
+ This field is required for trap generation upon MKey/BKey validation. */
+/* -------------- */
+};
+
+/* MAD_IFC Input Mailbox */
+
+struct arbelprm_mad_ifc_st { /* Little Endian */
+ pseudo_bit_t request_mad_packet[64][0x00020];/* Request MAD Packet (256bytes) */
+/* -------------- */
+ pseudo_bit_t my_qpn[0x00018]; /* Destination QP number from the received MAD.
+ This field is reserved if Mad_extended_info indication in the input modifier is clear. */
+ pseudo_bit_t reserved0[0x00008];
+/* -------------- */
+ pseudo_bit_t rqpn[0x00018]; /* Remote (source) QP number from the received MAD.
+ This field is reserved if Mad_extended_info indication in the input modifier is clear. */
+ pseudo_bit_t reserved1[0x00008];
+/* -------------- */
+ pseudo_bit_t rlid[0x00010]; /* Remote (source) LID from the received MAD.
+ This field is reserved if Mad_extended_info indication in the input modifier is clear. */
+ pseudo_bit_t ml_path[0x00007]; /* My (destination) LID path bits from the received MAD.
+ This field is reserved if Mad_extended_info indication in the input modifier is clear. */
+ pseudo_bit_t g[0x00001]; /* If set, the GRH field in valid.
+ This field is reserved if Mad_extended_info indication in the input modifier is clear. */
+ pseudo_bit_t reserved2[0x00004];
+ pseudo_bit_t sl[0x00004]; /* Service Level of the received MAD.
+ This field is reserved if Mad_extended_info indication in the input modifier is clear. */
+/* -------------- */
+ pseudo_bit_t pkey_indx[0x00010]; /* Index in PKey table that matches PKey of the received MAD.
+ This field is reserved if Mad_extended_info indication in the input modifier is clear. */
+ pseudo_bit_t reserved3[0x00010];
+/* -------------- */
+ pseudo_bit_t reserved4[0x00180];
+/* -------------- */
+ pseudo_bit_t grh[10][0x00020]; /* The GRH field of the MAD packet that was scattered to the first 40 bytes pointed to by the scatter list.
+ Valid if Mad_extended_info bit (in the input modifier) and g bit are set.
+ Otherwise this field is reserved. */
+/* -------------- */
+ pseudo_bit_t reserved5[0x004c0];
+/* -------------- */
+};
+
+/* Query Debug Message */
+
+struct arbelprm_query_debug_msg_st { /* Little Endian */
+ pseudo_bit_t phy_addr_h[0x00020]; /* Translation of the address in firmware area. High 32 bits. */
+/* -------------- */
+ pseudo_bit_t v[0x00001]; /* Physical translation is valid */
+ pseudo_bit_t reserved0[0x0000b];
+ pseudo_bit_t phy_addr_l[0x00014]; /* Translation of the address in firmware area. Low 32 bits. */
+/* -------------- */
+ pseudo_bit_t fw_area_base[0x00020]; /* Firmware area base address. The format strings and the trace buffers may be located starting from this address. */
+/* -------------- */
+ pseudo_bit_t fw_area_size[0x00020]; /* Firmware area size */
+/* -------------- */
+ pseudo_bit_t trc_hdr_sz[0x00020]; /* Trace message header size in dwords. */
+/* -------------- */
+ pseudo_bit_t trc_arg_num[0x00020]; /* The number of arguments per trace message. */
+/* -------------- */
+ pseudo_bit_t reserved1[0x000c0];
+/* -------------- */
+ pseudo_bit_t dbg_msk_h[0x00020]; /* Debug messages mask [63:32] */
+/* -------------- */
+ pseudo_bit_t dbg_msk_l[0x00020]; /* Debug messages mask [31:0] */
+/* -------------- */
+ pseudo_bit_t reserved2[0x00040];
+/* -------------- */
+ pseudo_bit_t buff0_addr[0x00020]; /* Address in firmware area of Trace Buffer 0 */
+/* -------------- */
+ pseudo_bit_t buff0_size[0x00020]; /* Size of Trace Buffer 0 */
+/* -------------- */
+ pseudo_bit_t buff1_addr[0x00020]; /* Address in firmware area of Trace Buffer 1 */
+/* -------------- */
+ pseudo_bit_t buff1_size[0x00020]; /* Size of Trace Buffer 1 */
+/* -------------- */
+ pseudo_bit_t buff2_addr[0x00020]; /* Address in firmware area of Trace Buffer 2 */
+/* -------------- */
+ pseudo_bit_t buff2_size[0x00020]; /* Size of Trace Buffer 2 */
+/* -------------- */
+ pseudo_bit_t buff3_addr[0x00020]; /* Address in firmware area of Trace Buffer 3 */
+/* -------------- */
+ pseudo_bit_t buff3_size[0x00020]; /* Size of Trace Buffer 3 */
+/* -------------- */
+ pseudo_bit_t buff4_addr[0x00020]; /* Address in firmware area of Trace Buffer 4 */
+/* -------------- */
+ pseudo_bit_t buff4_size[0x00020]; /* Size of Trace Buffer 4 */
+/* -------------- */
+ pseudo_bit_t buff5_addr[0x00020]; /* Address in firmware area of Trace Buffer 5 */
+/* -------------- */
+ pseudo_bit_t buff5_size[0x00020]; /* Size of Trace Buffer 5 */
+/* -------------- */
+ pseudo_bit_t buff6_addr[0x00020]; /* Address in firmware area of Trace Buffer 6 */
+/* -------------- */
+ pseudo_bit_t buff6_size[0x00020]; /* Size of Trace Buffer 6 */
+/* -------------- */
+ pseudo_bit_t buff7_addr[0x00020]; /* Address in firmware area of Trace Buffer 7 */
+/* -------------- */
+ pseudo_bit_t buff7_size[0x00020]; /* Size of Trace Buffer 7 */
+/* -------------- */
+ pseudo_bit_t reserved3[0x00400];
+/* -------------- */
+};
+
+/* User Access Region */
+
+struct arbelprm_uar_st { /* Little Endian */
+ struct arbelprm_rd_send_doorbell_st rd_send_doorbell;/* Reliable Datagram send doorbell */
+/* -------------- */
+ struct arbelprm_send_doorbell_st send_doorbell;/* Send doorbell */
+/* -------------- */
+ pseudo_bit_t reserved0[0x00040];
+/* -------------- */
+ struct arbelprm_cq_cmd_doorbell_st cq_command_doorbell;/* CQ Doorbell */
+/* -------------- */
+ pseudo_bit_t reserved1[0x03ec0];
+/* -------------- */
+};
+
+/* Receive doorbell */
+
+struct arbelprm_receive_doorbell_st { /* Little Endian */
+ pseudo_bit_t reserved0[0x00008];
+ pseudo_bit_t wqe_counter[0x00010]; /* Modulo-64K counter of WQEs posted on this queue since its creation. Should be zero for the first doorbell on the QP */
+ pseudo_bit_t reserved1[0x00008];
+/* -------------- */
+ pseudo_bit_t reserved2[0x00005];
+ pseudo_bit_t srq[0x00001]; /* If set, this is a Shared Receive Queue */
+ pseudo_bit_t reserved3[0x00002];
+ pseudo_bit_t qpn[0x00018]; /* QP number or SRQ number this doorbell is rung on */
+/* -------------- */
+};
+
+/* SET_IB Parameters */
+
+struct arbelprm_set_ib_st { /* Little Endian */
+ pseudo_bit_t rqk[0x00001]; /* Reset QKey Violation Counter */
+ pseudo_bit_t reserved0[0x00011];
+ pseudo_bit_t sig[0x00001]; /* Set System Image GUID to system_image_guid specified.
+ system_image_guid and sig must be the same for all ports. */
+ pseudo_bit_t reserved1[0x0000d];
+/* -------------- */
+ pseudo_bit_t capability_mask[0x00020];/* PortInfo Capability Mask */
+/* -------------- */
+ pseudo_bit_t system_image_guid_h[0x00020];/* System Image GUID[63:32], takes effect only if the SIG bit is set
+ Must be the same for both ports. */
+/* -------------- */
+ pseudo_bit_t system_image_guid_l[0x00020];/* System Image GUID[31:0], takes effect only if the SIG bit is set
+ Must be the same for both ports. */
+/* -------------- */
+ pseudo_bit_t reserved2[0x00180];
+/* -------------- */
+};
+
+/* Multicast Group Member */
+
+struct arbelprm_mgm_entry_st { /* Little Endian */
+ pseudo_bit_t reserved0[0x00006];
+ pseudo_bit_t next_gid_index[0x0001a];/* Index of next Multicast Group Member whose GID maps to same MGID_HASH number.
+ The index is into the Multicast Group Table, which is the comprised the MGHT and AMGM tables.
+ next_gid_index=0 means end of the chain. */
+/* -------------- */
+ pseudo_bit_t reserved1[0x00060];
+/* -------------- */
+ pseudo_bit_t mgid_128_96[0x00020]; /* Multicast group GID[128:96] in big endian format.
+ Use the Reserved GID 0:0:0:0:0:0:0:0 for an invalid entry. */
+/* -------------- */
+ pseudo_bit_t mgid_95_64[0x00020]; /* Multicast group GID[95:64] in big endian format.
+ Use the Reserved GID 0:0:0:0:0:0:0:0 for an invalid entry. */
+/* -------------- */
+ pseudo_bit_t mgid_63_32[0x00020]; /* Multicast group GID[63:32] in big endian format.
+ Use the Reserved GID 0:0:0:0:0:0:0:0 for an invalid entry. */
+/* -------------- */
+ pseudo_bit_t mgid_31_0[0x00020]; /* Multicast group GID[31:0] in big endian format.
+ Use the Reserved GID 0:0:0:0:0:0:0:0 for an invalid entry. */
+/* -------------- */
+ struct arbelprm_mgmqp_st mgmqp_0; /* Multicast Group Member QP */
+/* -------------- */
+ struct arbelprm_mgmqp_st mgmqp_1; /* Multicast Group Member QP */
+/* -------------- */
+ struct arbelprm_mgmqp_st mgmqp_2; /* Multicast Group Member QP */
+/* -------------- */
+ struct arbelprm_mgmqp_st mgmqp_3; /* Multicast Group Member QP */
+/* -------------- */
+ struct arbelprm_mgmqp_st mgmqp_4; /* Multicast Group Member QP */
+/* -------------- */
+ struct arbelprm_mgmqp_st mgmqp_5; /* Multicast Group Member QP */
+/* -------------- */
+ struct arbelprm_mgmqp_st mgmqp_6; /* Multicast Group Member QP */
+/* -------------- */
+ struct arbelprm_mgmqp_st mgmqp_7; /* Multicast Group Member QP */
+/* -------------- */
+};
+
+/* INIT_IB Parameters */
+
+struct arbelprm_init_ib_st { /* Little Endian */
+ pseudo_bit_t reserved0[0x00004];
+ pseudo_bit_t vl_cap[0x00004]; /* Maximum VLs supported on the port, excluding VL15.
+ Legal values are 1,2,4 and 8. */
+ pseudo_bit_t port_width_cap[0x00004];/* IB Port Width
+ 1 - 1x
+ 3 - 1x, 4x
+ 11 - 1x, 4x or 12x (must not be used in InfiniHost-III-EX MT25208)
+ else - Reserved */
+ pseudo_bit_t mtu_cap[0x00004]; /* Maximum MTU Supported
+ 0x0 - Reserved
+ 0x1 - 256
+ 0x2 - 512
+ 0x3 - 1024
+ 0x4 - 2048
+ 0x5 - 0xF Reserved */
+ pseudo_bit_t g0[0x00001]; /* Set port GUID0 to GUID0 specified */
+ pseudo_bit_t ng[0x00001]; /* Set node GUID to node_guid specified.
+ node_guid and ng must be the same for all ports. */
+ pseudo_bit_t sig[0x00001]; /* Set System Image GUID to system_image_guid specified.
+ system_image_guid and sig must be the same for all ports. */
+ pseudo_bit_t reserved1[0x0000d];
+/* -------------- */
+ pseudo_bit_t max_gid[0x00010]; /* Maximum number of GIDs for the port */
+ pseudo_bit_t reserved2[0x00010];
+/* -------------- */
+ pseudo_bit_t max_pkey[0x00010]; /* Maximum pkeys for the port.
+ Must be the same for both ports. */
+ pseudo_bit_t reserved3[0x00010];
+/* -------------- */
+ pseudo_bit_t reserved4[0x00020];
+/* -------------- */
+ pseudo_bit_t guid0_h[0x00020]; /* EUI-64 GUID assigned by the manufacturer, takes effect only if the G0 bit is set (bits 63:32) */
+/* -------------- */
+ pseudo_bit_t guid0_l[0x00020]; /* EUI-64 GUID assigned by the manufacturer, takes effect only if the G0 bit is set (bits 31:0) */
+/* -------------- */
+ pseudo_bit_t node_guid_h[0x00020]; /* Node GUID[63:32], takes effect only if the NG bit is set
+ Must be the same for both ports. */
+/* -------------- */
+ pseudo_bit_t node_guid_l[0x00020]; /* Node GUID[31:0], takes effect only if the NG bit is set
+ Must be the same for both ports. */
+/* -------------- */
+ pseudo_bit_t system_image_guid_h[0x00020];/* System Image GUID[63:32], takes effect only if the SIG bit is set
+ Must be the same for both ports. */
+/* -------------- */
+ pseudo_bit_t system_image_guid_l[0x00020];/* System Image GUID[31:0], takes effect only if the SIG bit is set
+ Must be the same for both ports. */
+/* -------------- */
+ pseudo_bit_t reserved5[0x006c0];
+/* -------------- */
+};
+
+/* Query Device Limitations */
+
+struct arbelprm_query_dev_lim_st { /* Little Endian */
+ pseudo_bit_t reserved0[0x00080];
+/* -------------- */
+ pseudo_bit_t log_max_qp[0x00005]; /* Log2 of the Maximum number of QPs supported */
+ pseudo_bit_t reserved1[0x00003];
+ pseudo_bit_t log2_rsvd_qps[0x00004];/* Log (base 2) of the number of QPs reserved for firmware use
+ The reserved resources are numbered from 0 to 2^log2_rsvd_qps-1 */
+ pseudo_bit_t reserved2[0x00004];
+ pseudo_bit_t log_max_qp_sz[0x00008];/* The maximum number of WQEs allowed on the RQ or the SQ is 2^log_max_qp_sz-1 */
+ pseudo_bit_t log_max_srq_sz[0x00008];/* The maximum number of WQEs allowed on the SRQ is 2^log_max_srq_sz-1 */
+/* -------------- */
+ pseudo_bit_t log_max_ee[0x00005]; /* Log2 of the Maximum number of EE contexts supported */
+ pseudo_bit_t reserved3[0x00003];
+ pseudo_bit_t log2_rsvd_ees[0x00004];/* Log (base 2) of the number of EECs reserved for firmware use
+ The reserved resources are numbered from 0 to 2^log2_rsvd_ees-1 */
+ pseudo_bit_t reserved4[0x00004];
+ pseudo_bit_t log_max_srqs[0x00005]; /* Log base 2 of the maximum number of SRQs supported, valid only if SRQ bit is set.
+ */
+ pseudo_bit_t reserved5[0x00007];
+ pseudo_bit_t log2_rsvd_srqs[0x00004];/* Log (base 2) of the number of reserved SRQs for firmware use
+ The reserved resources are numbered from 0 to 2^log2_rsvd_srqs-1
+ This parameter is valid only if the SRQ bit is set. */
+/* -------------- */
+ pseudo_bit_t log_max_cq[0x00005]; /* Log2 of the Maximum number of CQs supported */
+ pseudo_bit_t reserved6[0x00003];
+ pseudo_bit_t log2_rsvd_cqs[0x00004];/* Log (base 2) of the number of CQs reserved for firmware use
+ The reserved resources are numbered from 0 to 2^log2_rsrvd_cqs-1 */
+ pseudo_bit_t reserved7[0x00004];
+ pseudo_bit_t log_max_cq_sz[0x00008];/* Log2 of the Maximum CQEs allowed in a CQ */
+ pseudo_bit_t reserved8[0x00008];
+/* -------------- */
+ pseudo_bit_t log_max_eq[0x00003]; /* Log2 of the Maximum number of EQs */
+ pseudo_bit_t reserved9[0x00005];
+ pseudo_bit_t num_rsvd_eqs[0x00004]; /* The number of EQs reserved for firmware use
+ The reserved resources are numbered from 0 to num_rsvd_eqs-1
+ If 0 - no resources are reserved. */
+ pseudo_bit_t reserved10[0x00004];
+ pseudo_bit_t log_max_mpts[0x00006]; /* Log (base 2) of the maximum number of MPT entries (the number of Regions/Windows) */
+ pseudo_bit_t reserved11[0x00002];
+ pseudo_bit_t log_max_eq_sz[0x00008];/* Log2 of the Maximum EQEs allowed in a EQ */
+/* -------------- */
+ pseudo_bit_t log_max_mtts[0x00006]; /* Log2 of the Maximum number of MTT entries */
+ pseudo_bit_t reserved12[0x00002];
+ pseudo_bit_t log2_rsvd_mrws[0x00004];/* Log (base 2) of the number of MPTs reserved for firmware use
+ The reserved resources are numbered from 0 to 2^log2_rsvd_mrws-1 */
+ pseudo_bit_t reserved13[0x00004];
+ pseudo_bit_t log_max_mrw_sz[0x00008];/* Log2 of the Maximum Size of Memory Region/Window */
+ pseudo_bit_t reserved14[0x00004];
+ pseudo_bit_t log2_rsvd_mtts[0x00004];/* Log (base 2) of the number of MTT entries reserved for firmware use
+ The reserved resources are numbered from 0 to 2^log2_rsvd_mtts-1
+ */
+/* -------------- */
+ pseudo_bit_t reserved15[0x00020];
+/* -------------- */
+ pseudo_bit_t log_max_ra_res_qp[0x00006];/* Log2 of the Maximum number of outstanding RDMA read/Atomic per QP as a responder */
+ pseudo_bit_t reserved16[0x0000a];
+ pseudo_bit_t log_max_ra_req_qp[0x00006];/* Log2 of the maximum number of outstanding RDMA read/Atomic per QP as a requester */
+ pseudo_bit_t reserved17[0x0000a];
+/* -------------- */
+ pseudo_bit_t log_max_ra_res_global[0x00006];/* Log2 of the maximum number of RDMA read/atomic operations the HCA responder can support globally. That implies the RDB table size. */
+ pseudo_bit_t reserved18[0x00016];
+ pseudo_bit_t log2_rsvd_rdbs[0x00004];/* Log (base 2) of the number of RDB entries reserved for firmware use
+ The reserved resources are numbered from 0 to 2^log2_rsvd_rdbs-1 */
+/* -------------- */
+ pseudo_bit_t rsz_srq[0x00001]; /* Ability to modify the maximum number of WRs per SRQ. */
+ pseudo_bit_t reserved19[0x0001f];
+/* -------------- */
+ pseudo_bit_t num_ports[0x00004]; /* Number of IB ports. */
+ pseudo_bit_t max_vl[0x00004]; /* Maximum VLs supported on each port, excluding VL15 */
+ pseudo_bit_t max_port_width[0x00004];/* IB Port Width
+ 1 - 1x
+ 3 - 1x, 4x
+ 11 - 1x, 4x or 12x
+ else - Reserved */
+ pseudo_bit_t max_mtu[0x00004]; /* Maximum MTU Supported
+ 0x0 - Reserved
+ 0x1 - 256
+ 0x2 - 512
+ 0x3 - 1024
+ 0x4 - 2048
+ 0x5 - 0xF Reserved */
+ pseudo_bit_t local_ca_ack_delay[0x00005];/* The Local CA ACK Delay. This is the value recommended to be returned in Query HCA verb.
+ The delay value in microseconds is computed using 4.096us * 2^(local_ca_ack_delay). */
+ pseudo_bit_t reserved20[0x0000b];
+/* -------------- */
+ pseudo_bit_t log_max_gid[0x00004]; /* Log2 of the maximum number of GIDs per port */
+ pseudo_bit_t reserved21[0x0001c];
+/* -------------- */
+ pseudo_bit_t log_max_pkey[0x00004]; /* Log2 of the max PKey Table Size (per IB port) */
+ pseudo_bit_t reserved22[0x0000c];
+ pseudo_bit_t stat_rate_support[0x00010];/* bit mask of stat rate supported
+ bit 0 - full bw
+ bit 1 - 1/4 bw
+ bit 2 - 1/8 bw
+ bit 3 - 1/2 bw; */
+/* -------------- */
+ pseudo_bit_t reserved23[0x00020];
+/* -------------- */
+ pseudo_bit_t rc[0x00001]; /* RC Transport supported */
+ pseudo_bit_t uc[0x00001]; /* UC Transport Supported */
+ pseudo_bit_t ud[0x00001]; /* UD Transport Supported */
+ pseudo_bit_t rd[0x00001]; /* RD Transport Supported */
+ pseudo_bit_t raw_ipv6[0x00001]; /* Raw IPv6 Transport Supported */
+ pseudo_bit_t raw_ether[0x00001]; /* Raw Ethertype Transport Supported */
+ pseudo_bit_t srq[0x00001]; /* SRQ is supported
+ */
+ pseudo_bit_t ipo_ib_checksum[0x00001];/* IP over IB checksum is supported */
+ pseudo_bit_t pkv[0x00001]; /* PKey Violation Counter Supported */
+ pseudo_bit_t qkv[0x00001]; /* QKey Violation Coutner Supported */
+ pseudo_bit_t reserved24[0x00006];
+ pseudo_bit_t mw[0x00001]; /* Memory windows supported */
+ pseudo_bit_t apm[0x00001]; /* Automatic Path Migration Supported */
+ pseudo_bit_t atm[0x00001]; /* Atomic operations supported (atomicity is guaranteed between QPs on this HCA) */
+ pseudo_bit_t rm[0x00001]; /* Raw Multicast Supported */
+ pseudo_bit_t avp[0x00001]; /* Address Vector Port checking supported */
+ pseudo_bit_t udm[0x00001]; /* UD Multicast Supported */
+ pseudo_bit_t reserved25[0x00002];
+ pseudo_bit_t pg[0x00001]; /* Paging on demand supported */
+ pseudo_bit_t r[0x00001]; /* Router mode supported */
+ pseudo_bit_t reserved26[0x00006];
+/* -------------- */
+ pseudo_bit_t log_pg_sz[0x00008]; /* Minimum system page size supported (log2).
+ For proper operation it must be less than or equal the hosting platform (CPU) minimum page size. */
+ pseudo_bit_t reserved27[0x00008];
+ pseudo_bit_t uar_sz[0x00006]; /* UAR Area Size = 1MB * 2^uar_sz */
+ pseudo_bit_t reserved28[0x00006];
+ pseudo_bit_t num_rsvd_uars[0x00004];/* The number of UARs reserved for firmware use
+ The reserved resources are numbered from 0 to num_reserved_uars-1
+ Note that UAR number num_reserved_uars is always for the kernel. */
+/* -------------- */
+ pseudo_bit_t reserved29[0x00020];
+/* -------------- */
+ pseudo_bit_t max_desc_sz_sq[0x00010];/* Max descriptor size in bytes for the send queue */
+ pseudo_bit_t max_sg_sq[0x00008]; /* The maximum S/G list elements in a SQ WQE (max_desc_sz/16 - 3) */
+ pseudo_bit_t reserved30[0x00008];
+/* -------------- */
+ pseudo_bit_t max_desc_sz_rq[0x00010];/* Max descriptor size in bytes for the receive queue */
+ pseudo_bit_t max_sg_rq[0x00008]; /* The maximum S/G list elements in a RQ WQE (max_desc_sz/16 - 3) */
+ pseudo_bit_t reserved31[0x00008];
+/* -------------- */
+ pseudo_bit_t reserved32[0x00040];
+/* -------------- */
+ pseudo_bit_t log_max_mcg[0x00008]; /* Log2 of the maximum number of multicast groups */
+ pseudo_bit_t num_rsvd_mcgs[0x00004];/* The number of MGMs reserved for firmware use in the MGHT.
+ The reserved resources are numbered from 0 to num_reserved_mcgs-1
+ If 0 - no resources are reserved. */
+ pseudo_bit_t reserved33[0x00004];
+ pseudo_bit_t log_max_qp_mcg[0x00008];/* Log2 of the maximum number of QPs per multicast group */
+ pseudo_bit_t reserved34[0x00008];
+/* -------------- */
+ pseudo_bit_t log_max_rdds[0x00006]; /* Log2 of the maximum number of RDDs */
+ pseudo_bit_t reserved35[0x00006];
+ pseudo_bit_t num_rsvd_rdds[0x00004];/* The number of RDDs reserved for firmware use
+ The reserved resources are numbered from 0 to num_reserved_rdds-1.
+ If 0 - no resources are reserved. */
+ pseudo_bit_t log_max_pd[0x00006]; /* Log2 of the maximum number of PDs */
+ pseudo_bit_t reserved36[0x00006];
+ pseudo_bit_t num_rsvd_pds[0x00004]; /* The number of PDs reserved for firmware use
+ The reserved resources are numbered from 0 to num_reserved_pds-1
+ If 0 - no resources are reserved. */
+/* -------------- */
+ pseudo_bit_t reserved37[0x000c0];
+/* -------------- */
+ pseudo_bit_t qpc_entry_sz[0x00010]; /* QPC Entry Size for the device
+ For the InfiniHost-III-EX MT25208 entry size is 256 bytes */
+ pseudo_bit_t eec_entry_sz[0x00010]; /* EEC Entry Size for the device
+ For the InfiniHost-III-EX MT25208 entry size is 256 bytes */
+/* -------------- */
+ pseudo_bit_t eqpc_entry_sz[0x00010];/* Extended QPC entry size for the device
+ For the InfiniHost-III-EX MT25208 entry size is 32 bytes */
+ pseudo_bit_t eeec_entry_sz[0x00010];/* Extended EEC entry size for the device
+ For the InfiniHost-III-EX MT25208 entry size is 32 bytes */
+/* -------------- */
+ pseudo_bit_t cqc_entry_sz[0x00010]; /* CQC entry size for the device
+ For the InfiniHost-III-EX MT25208 entry size is 64 bytes */
+ pseudo_bit_t eqc_entry_sz[0x00010]; /* EQ context entry size for the device
+ For the InfiniHost-III-EX MT25208 entry size is 64 bytes */
+/* -------------- */
+ pseudo_bit_t uar_scratch_entry_sz[0x00010];/* UAR Scratchpad Entry Size
+ For the InfiniHost-III-EX MT25208 entry size is 32 bytes */
+ pseudo_bit_t srq_entry_sz[0x00010]; /* SRQ context entry size for the device
+ For the InfiniHost-III-EX MT25208 entry size is 32 bytes */
+/* -------------- */
+ pseudo_bit_t mpt_entry_sz[0x00010]; /* MPT entry size in Bytes for the device.
+ For the InfiniHost-III-EX MT25208 entry size is 64 bytes */
+ pseudo_bit_t mtt_entry_sz[0x00010]; /* MTT entry size in Bytes for the device.
+ For the InfiniHost-III-EX MT25208 entry size is 8 bytes */
+/* -------------- */
+ pseudo_bit_t bmme[0x00001]; /* Base Memory Management Extension Support */
+ pseudo_bit_t win_type[0x00001]; /* Bound Type 2 Memory Window Association mechanism:
+ 0 - Type 2A - QP Number Association; or
+ 1 - Type 2B - QP Number and PD Association. */
+ pseudo_bit_t mps[0x00001]; /* Ability of this HCA to support multiple page sizes per Memory Region. */
+ pseudo_bit_t bl[0x00001]; /* Ability of this HCA to support Block List Physical Buffer Lists. (The device does not supports Block List) */
+ pseudo_bit_t zb[0x00001]; /* Zero Based region/windows supported */
+ pseudo_bit_t lif[0x00001]; /* Ability of this HCA to support Local Invalidate Fencing. */
+ pseudo_bit_t reserved38[0x00002];
+ pseudo_bit_t log_pbl_sz[0x00006]; /* Log2 of the Maximum Physical Buffer List size in Bytes supported by this HCA when invoking the Allocate L_Key verb.
+ */
+ pseudo_bit_t reserved39[0x00012];
+/* -------------- */
+ pseudo_bit_t resd_lkey[0x00020]; /* The value of the reserved Lkey for Base Memory Management Extension */
+/* -------------- */
+ pseudo_bit_t lamr[0x00001]; /* When set the device requires local attached memory in order to operate.
+ When set, ICM pages, Firmware Area and ICM auxiliary pages must be allocated in the local attached memory. */
+ pseudo_bit_t reserved40[0x0001f];
+/* -------------- */
+ pseudo_bit_t max_icm_size_h[0x00020];/* Bits [63:32] of maximum ICM size InfiniHost III Ex support in bytes. */
+/* -------------- */
+ pseudo_bit_t max_icm_size_l[0x00020];/* Bits [31:0] of maximum ICM size InfiniHost III Ex support in bytes. */
+/* -------------- */
+ pseudo_bit_t reserved41[0x002c0];
+/* -------------- */
+};
+
+/* QUERY_ADAPTER Parameters Block */
+
+struct arbelprm_query_adapter_st { /* Little Endian */
+ pseudo_bit_t reserved0[0x00080];
+/* -------------- */
+ pseudo_bit_t reserved1[0x00018];
+ pseudo_bit_t intapin[0x00008]; /* Driver should set this field to INTR value in the event queue in order to get Express interrupt messages. */
+/* -------------- */
+ pseudo_bit_t reserved2[0x00060];
+/* -------------- */
+ struct arbelprm_vsd_st vsd;
+/* -------------- */
+};
+
+/* QUERY_FW Parameters Block */
+
+struct arbelprm_query_fw_st { /* Little Endian */
+ pseudo_bit_t fw_rev_major[0x00010]; /* Firmware Revision - Major */
+ pseudo_bit_t fw_pages[0x00010]; /* Amount of physical memory to be allocated for FW usage is in 4KByte pages. */
+/* -------------- */
+ pseudo_bit_t fw_rev_minor[0x00010]; /* Firmware Revision - Minor */
+ pseudo_bit_t fw_rev_subminor[0x00010];/* Firmware Sub-minor version (Patch level). */
+/* -------------- */
+ pseudo_bit_t cmd_interface_rev[0x00010];/* Command Interface Interpreter Revision ID */
+ pseudo_bit_t reserved0[0x0000e];
+ pseudo_bit_t wqe_h_mode[0x00001]; /* Hermon mode. If '1', then WQE and AV format is the advanced format */
+ pseudo_bit_t zb_wq_cq[0x00001]; /* If '1', then ZB mode of WQ and CQ are enabled (i.e. real Memfree PRM is supported) */
+/* -------------- */
+ pseudo_bit_t log_max_outstanding_cmd[0x00008];/* Log2 of the maximum number of commands the HCR can support simultaneously */
+ pseudo_bit_t reserved1[0x00017];
+ pseudo_bit_t dt[0x00001]; /* Debug Trace Support
+ 0 - Debug trace is not supported
+ 1 - Debug trace is supported */
+/* -------------- */
+ pseudo_bit_t cmd_interface_db[0x00001];/* Set if the device accepts commands by means of special doorbells */
+ pseudo_bit_t reserved2[0x0001f];
+/* -------------- */
+ pseudo_bit_t reserved3[0x00060];
+/* -------------- */
+ pseudo_bit_t clr_int_base_addr_h[0x00020];/* Bits [63:32] of Clear interrupt register physical address.
+ Points to 64 bit register. */
+/* -------------- */
+ pseudo_bit_t clr_int_base_addr_l[0x00020];/* Bits [31:0] of Clear interrupt register physical address.
+ Points to 64 bit register. */
+/* -------------- */
+ pseudo_bit_t reserved4[0x00040];
+/* -------------- */
+ pseudo_bit_t error_buf_start_h[0x00020];/* Read Only buffer for catastrophic error reports (physical address) */
+/* -------------- */
+ pseudo_bit_t error_buf_start_l[0x00020];/* Read Only buffer for catastrophic error reports (physical address) */
+/* -------------- */
+ pseudo_bit_t error_buf_size[0x00020];/* Size in words */
+/* -------------- */
+ pseudo_bit_t reserved5[0x00020];
+/* -------------- */
+ pseudo_bit_t eq_arm_base_addr_h[0x00020];/* Bits [63:32] of EQ Arm DBs physical address.
+ Points to 64 bit register.
+ Setting bit x in the offset, arms EQ number x.
+ */
+/* -------------- */
+ pseudo_bit_t eq_arm_base_addr_l[0x00020];/* Bits [31:0] of EQ Arm DBs physical address.
+ Points to 64 bit register.
+ Setting bit x in the offset, arms EQ number x. */
+/* -------------- */
+ pseudo_bit_t eq_set_ci_base_addr_h[0x00020];/* Bits [63:32] of EQ Set CI DBs Table physical address.
+ Points to a the EQ Set CI DBs Table base address. */
+/* -------------- */
+ pseudo_bit_t eq_set_ci_base_addr_l[0x00020];/* Bits [31:0] of EQ Set CI DBs Table physical address.
+ Points to a the EQ Set CI DBs Table base address. */
+/* -------------- */
+ pseudo_bit_t cmd_db_dw1[0x00010]; /* offset in bytes from cmd_db_addr_base where DWord 1 of a Command Interface Doorbell should be written. Valid only if CmdInterfaceDb bit is '1' */
+ pseudo_bit_t cmd_db_dw0[0x00010]; /* offset in bytes from cmd_db_addr_base where DWord 0 of a Command Interface Doorbell should be written. Valid only if CmdInterfaceDb bit is '1' */
+/* -------------- */
+ pseudo_bit_t cmd_db_dw3[0x00010]; /* offset in bytes from cmd_db_addr_base where DWord 3 of a Command Interface Doorbell should be written. Valid only if CmdInterfaceDb bit is '1' */
+ pseudo_bit_t cmd_db_dw2[0x00010]; /* offset in bytes from cmd_db_addr_base where DWord 2 of a Command Interface Doorbell should be written. Valid only if CmdInterfaceDb bit is '1' */
+/* -------------- */
+ pseudo_bit_t cmd_db_dw5[0x00010]; /* offset in bytes from cmd_db_addr_base where DWord 5 of a Command Interface Doorbell should be written. Valid only if CmdInterfaceDb bit is '1' */
+ pseudo_bit_t cmd_db_dw4[0x00010]; /* offset in bytes from cmd_db_addr_base where DWord 4 of a Command Interface Doorbell should be written. Valid only if CmdInterfaceDb bit is '1' */
+/* -------------- */
+ pseudo_bit_t cmd_db_dw7[0x00010]; /* offset in bytes from cmd_db_addr_base where DWord 7 of a Command Interface Doorbell should be written. Valid only if CmdInterfaceDb bit is '1' */
+ pseudo_bit_t cmd_db_dw6[0x00010]; /* offset in bytes from cmd_db_addr_base where DWord 6 of a Command Interface Doorbell should be written. Valid only if CmdInterfaceDb bit is '1' */
+/* -------------- */
+ pseudo_bit_t cmd_db_addr_base_h[0x00020];/* High bits of cmd_db_addr_base, which cmd_db_dw offsets refer to. Valid only if CmdInterfaceDb bit is '1' */
+/* -------------- */
+ pseudo_bit_t cmd_db_addr_base_l[0x00020];/* Low bits of cmd_db_addr_base, which cmd_db_dw offsets refer to. Valid only if CmdInterfaceDb bit is '1' */
+/* -------------- */
+ pseudo_bit_t reserved6[0x004c0];
+/* -------------- */
+};
+
+/* ACCESS_LAM */
+
+struct arbelprm_access_lam_st { /* Little Endian */
+ struct arbelprm_access_lam_inject_errors_st access_lam_inject_errors;
+/* -------------- */
+ pseudo_bit_t reserved0[0x00080];
+/* -------------- */
+};
+
+/* ENABLE_LAM Parameters Block */
+
+struct arbelprm_enable_lam_st { /* Little Endian */
+ pseudo_bit_t lam_start_adr_h[0x00020];/* LAM start address [63:32] */
+/* -------------- */
+ pseudo_bit_t lam_start_adr_l[0x00020];/* LAM start address [31:0] */
+/* -------------- */
+ pseudo_bit_t lam_end_adr_h[0x00020];/* LAM end address [63:32] */
+/* -------------- */
+ pseudo_bit_t lam_end_adr_l[0x00020];/* LAM end address [31:0] */
+/* -------------- */
+ pseudo_bit_t di[0x00002]; /* Data Integrity Configuration:
+ 00 - none
+ 01 - Parity
+ 10 - ECC Detection Only
+ 11 - ECC With Correction */
+ pseudo_bit_t ap[0x00002]; /* Auto Precharge Mode
+ 00 - No auto precharge
+ 01 - Auto precharge per transaction
+ 10 - Auto precharge per 64 bytes
+ 11 - reserved */
+ pseudo_bit_t dh[0x00001]; /* When set, LAM is Hidden and can not be accessed directly from the PCI bus. */
+ pseudo_bit_t reserved0[0x0001b];
+/* -------------- */
+ pseudo_bit_t reserved1[0x00160];
+/* -------------- */
+ struct arbelprm_dimminfo_st dimm0; /* Logical DIMM 0 Parameters */
+/* -------------- */
+ struct arbelprm_dimminfo_st dimm1; /* Logical DIMM 1 Parameters */
+/* -------------- */
+ pseudo_bit_t reserved2[0x00400];
+/* -------------- */
+};
+
+/* Memory Access Parameters for UD Address Vector Table */
+
+struct arbelprm_udavtable_memory_parameters_st { /* Little Endian */
+ pseudo_bit_t l_key[0x00020]; /* L_Key used to access TPT */
+/* -------------- */
+ pseudo_bit_t pd[0x00018]; /* PD used by TPT for matching against PD of region entry being accessed. */
+ pseudo_bit_t reserved0[0x00005];
+ pseudo_bit_t xlation_en[0x00001]; /* When cleared, address is physical address and no translation will be done. When set, address is virtual. */
+ pseudo_bit_t reserved1[0x00002];
+/* -------------- */
+};
+
+/* INIT_HCA & QUERY_HCA Parameters Block */
+
+struct arbelprm_init_hca_st { /* Little Endian */
+ pseudo_bit_t reserved0[0x00060];
+/* -------------- */
+ pseudo_bit_t reserved1[0x00010];
+ pseudo_bit_t time_stamp_granularity[0x00008];/* This field controls the granularity in which CQE Timestamp counter is incremented.
+ The TimeStampGranularity units is 1/4 of a microseconds. (e.g is TimeStampGranularity is configured to 0x2, CQE Timestamp will be incremented every one microsecond)
+ When sets to Zero, timestamp reporting in the CQE is disabled.
+ This feature is currently not supported.
+ */
+ pseudo_bit_t hca_core_clock[0x00008];/* Internal Clock Period (in units of 1/16 ns) (QUERY_HCA only) */
+/* -------------- */
+ pseudo_bit_t reserved2[0x00008];
+ pseudo_bit_t router_qp[0x00010]; /* Upper 16 bit to be used as a QP number for router mode. Low order 8 bits are taken from the TClass field of the incoming packet.
+ Valid only if RE bit is set */
+ pseudo_bit_t reserved3[0x00007];
+ pseudo_bit_t re[0x00001]; /* Router Mode Enable
+ If this bit is set, entire packet (including all headers and ICRC) will be considered as a data payload and will be scattered to memory as specified in the descriptor that is posted on the QP matching the TClass field of packet. */
+/* -------------- */
+ pseudo_bit_t udp[0x00001]; /* UD Port Check Enable
+ 0 - Port field in Address Vector is ignored
+ 1 - HCA will check the port field in AV entry (fetched for UD descriptor) against the Port of the UD QP executing the descriptor. */
+ pseudo_bit_t he[0x00001]; /* Host Endianess - Used for Atomic Operations
+ 0 - Host is Little Endian
+ 1 - Host is Big endian
+ */
+ pseudo_bit_t reserved4[0x00001];
+ pseudo_bit_t ce[0x00001]; /* Checksum Enabled - when Set IPoverIB checksum generation & checking is enabled */
+ pseudo_bit_t sph[0x00001]; /* 0 - SW calculates TCP/UDP Pseudo-Header checksum and inserts it into the TCP/UDP checksum field when sending a packet
+ 1 - HW calculates TCP/UDP Pseudo-Header checksum when sending a packet
+ */
+ pseudo_bit_t rph[0x00001]; /* 0 - Not HW calculation of TCP/UDP Pseudo-Header checksum are done when receiving a packet
+ 1 - HW calculates TCP/UDP Pseudo-Header checksum when receiving a packet
+ */
+ pseudo_bit_t reserved5[0x00002];
+ pseudo_bit_t responder_exu[0x00004];/* Indicate the relation between the execution enegines allocation dedicated for responder versus the engines dedicated for reqvester .
+ responder_exu/16 = (number of responder exu engines)/(total number of engines)
+ Legal values are 0x0-0xF. 0 is "auto".
+
+ */
+ pseudo_bit_t reserved6[0x00004];
+ pseudo_bit_t wqe_quota[0x0000f]; /* Maximum number of WQEs that are executed prior to preemption of execution unit. 0 - reserved. */
+ pseudo_bit_t wqe_quota_en[0x00001]; /* If set - wqe_quota field is used. If cleared - WQE quota is set to "auto" value */
+/* -------------- */
+ pseudo_bit_t reserved7[0x00040];
+/* -------------- */
+ struct arbelprm_qpcbaseaddr_st qpc_eec_cqc_eqc_rdb_parameters;
+/* -------------- */
+ pseudo_bit_t reserved8[0x00100];
+/* -------------- */
+ struct arbelprm_multicastparam_st multicast_parameters;
+/* -------------- */
+ pseudo_bit_t reserved9[0x00080];
+/* -------------- */
+ struct arbelprm_tptparams_st tpt_parameters;
+/* -------------- */
+ pseudo_bit_t reserved10[0x00080];
+/* -------------- */
+ struct arbelprm_uar_params_st uar_parameters;/* UAR Parameters */
+/* -------------- */
+ pseudo_bit_t reserved11[0x00600];
+/* -------------- */
+};
+
+/* Event Queue Context Table Entry */
+
+struct arbelprm_eqc_st { /* Little Endian */
+ pseudo_bit_t reserved0[0x00008];
+ pseudo_bit_t st[0x00004]; /* Event delivery state machine
+ 0x9 - Armed
+ 0xA - Fired
+ 0xB - Always_Armed (auto-rearm)
+ other - reserved */
+ pseudo_bit_t reserved1[0x00005];
+ pseudo_bit_t oi[0x00001]; /* Oerrun ignore.
+ If set, HW will not check EQ full condition when writing new EQEs. */
+ pseudo_bit_t tr[0x00001]; /* Translation Required. If set - EQ access undergo address translation. */
+ pseudo_bit_t reserved2[0x00005];
+ pseudo_bit_t owner[0x00004]; /* 0 - SW ownership
+ 1 - HW ownership
+ Valid for the QUERY_EQ and HW2SW_EQ commands only */
+ pseudo_bit_t status[0x00004]; /* EQ status:
+ 0000 - OK
+ 1010 - EQ write failure
+ Valid for the QUERY_EQ and HW2SW_EQ commands only */
+/* -------------- */
+ pseudo_bit_t start_address_h[0x00020];/* Start Address of Event Queue[63:32]. */
+/* -------------- */
+ pseudo_bit_t start_address_l[0x00020];/* Start Address of Event Queue[31:0].
+ Must be aligned on 32-byte boundary */
+/* -------------- */
+ pseudo_bit_t reserved3[0x00018];
+ pseudo_bit_t log_eq_size[0x00005]; /* Amount of entries in this EQ is 2^log_eq_size.
+ Log_eq_size must be bigger than 1.
+ Maximum EQ size is 2^17 EQEs (max Log_eq_size is 17). */
+ pseudo_bit_t reserved4[0x00003];
+/* -------------- */
+ pseudo_bit_t reserved5[0x00020];
+/* -------------- */
+ pseudo_bit_t intr[0x00008]; /* Interrupt (message) to be generated to report event to INT layer.
+ 00iiiiii - set to INTA given in QUERY_ADAPTER in order to generate INTA messages on Express.
+ 10jjjjjj - specificies type of interrupt message to be generated (total 64 different messages supported).
+ All other values are reserved and should not be used.
+
+ If interrupt generation is not required, ST field must be set upon creation to Fired state. No EQ arming doorbell should be performed. In this case hardware will not generate any interrupt. */
+ pseudo_bit_t reserved6[0x00018];
+/* -------------- */
+ pseudo_bit_t pd[0x00018]; /* PD to be used to access EQ */
+ pseudo_bit_t reserved7[0x00008];
+/* -------------- */
+ pseudo_bit_t lkey[0x00020]; /* Memory key (L-Key) to be used to access EQ */
+/* -------------- */
+ pseudo_bit_t reserved8[0x00040];
+/* -------------- */
+ pseudo_bit_t consumer_indx[0x00020];/* Contains next entry to be read upon polling the event queue.
+ Must be initalized to zero while opening EQ */
+/* -------------- */
+ pseudo_bit_t producer_indx[0x00020];/* Contains next entry in EQ to be written by the HCA.
+ Must be initalized to zero while opening EQ. */
+/* -------------- */
+ pseudo_bit_t reserved9[0x00080];
+/* -------------- */
+};
+
+/* Memory Translation Table (MTT) Entry */
+
+struct arbelprm_mtt_st { /* Little Endian */
+ pseudo_bit_t ptag_h[0x00020]; /* High-order bits of physical tag. The size of the field depends on the page size of the region. Maximum PTAG size is 52 bits. */
+/* -------------- */
+ pseudo_bit_t p[0x00001]; /* Present bit. If set, page entry is valid. If cleared, access to this page will generate non-present page access fault. */
+ pseudo_bit_t reserved0[0x0000b];
+ pseudo_bit_t ptag_l[0x00014]; /* Low-order bits of Physical tag. The size of the field depends on the page size of the region. Maximum PTAG size is 52 bits. */
+/* -------------- */
+};
+
+/* Memory Protection Table (MPT) Entry */
+
+struct arbelprm_mpt_st { /* Little Endian */
+ pseudo_bit_t reserved0[0x00008];
+ pseudo_bit_t r_w[0x00001]; /* Defines whether this entry is Region (1) or Window (0) */
+ pseudo_bit_t pa[0x00001]; /* Physical address. If set, no virtual-to-physical address translation will be performed for this region */
+ pseudo_bit_t lr[0x00001]; /* If set - local read access enabled */
+ pseudo_bit_t lw[0x00001]; /* If set - local write access enabled */
+ pseudo_bit_t rr[0x00001]; /* If set - remote read access enabled. */
+ pseudo_bit_t rw[0x00001]; /* If set - remote write access enabled */
+ pseudo_bit_t a[0x00001]; /* If set - remote Atomic access is enabled */
+ pseudo_bit_t eb[0x00001]; /* If set - Bind is enabled. Valid for region entry only. */
+ pseudo_bit_t reserved1[0x0000c];
+ pseudo_bit_t status[0x00004]; /* Region/Window Status
+ 0xF - not valid (SW ownership)
+ 0x3 - FREE state
+ else - HW ownership
+ Unbound Type I windows are doneted reg_wnd_len field equals zero.
+ Unbound Type II windows are donated by Status=FREE. */
+/* -------------- */
+ pseudo_bit_t page_size[0x00005]; /* Page size used for the region. Actual size is [4K]*2^Page_size bytes.
+ page_size should be less than 20. */
+ pseudo_bit_t reserved2[0x00002];
+ pseudo_bit_t type[0x00001]; /* Applicable for windows only, must be zero for regions
+ 0 - Type one window
+ 1 - Type two window */
+ pseudo_bit_t qpn[0x00018]; /* QP number this MW is attached to. Valid for type2 memory windows and on QUERY_MPT only */
+/* -------------- */
+ pseudo_bit_t mem_key[0x00020]; /* The memory Key. The field holds the mem_key field in the following semantics: {key[7:0],key[31:8]}.
+ */
+/* -------------- */
+ pseudo_bit_t pd[0x00018]; /* Protection Domain */
+ pseudo_bit_t reserved3[0x00001];
+ pseudo_bit_t ei[0x00001]; /* Enable Invalidation - When set, Local/Remote invalidation can be executed on this window/region.
+ Must be set for type2 windows and non-shared physical memory regions.
+ Must be clear for regions that are used to access Work Queues, Completion Queues and Event Queues */
+ pseudo_bit_t zb[0x00001]; /* When set, this region is Zero Based Region */
+ pseudo_bit_t fre[0x00001]; /* When set, Fast Registration Operations can be executed on this region */
+ pseudo_bit_t rae[0x00001]; /* When set, remote access can be enabled on this region.
+ Used when executing Fast Registration Work Request to validate that remote access rights can be granted to this MPT.
+ If the bit is cleared, Fast Registration Work Request requesting remote access rights will fail.
+ */
+ pseudo_bit_t reserved4[0x00003];
+/* -------------- */
+ pseudo_bit_t start_address_h[0x00020];/* Start Address[63:32] - Virtual Address where this region/window starts */
+/* -------------- */
+ pseudo_bit_t start_address_l[0x00020];/* Start Address[31:0] - Virtual Address where this region/window starts */
+/* -------------- */
+ pseudo_bit_t reg_wnd_len_h[0x00020];/* Region/Window Length[63:32] */
+/* -------------- */
+ pseudo_bit_t reg_wnd_len_l[0x00020];/* Region/Window Length[31:0] */
+/* -------------- */
+ pseudo_bit_t lkey[0x00020]; /* Must be 0 for SW2HW_MPT.
+ On QUERY_MPT and HW2SW_MPT commands for Memory Window it reflects the LKey of the Region that the Window is bound to.
+ The field holds the lkey field in the following semantics: {key[7:0],key[31:8]}. */
+/* -------------- */
+ pseudo_bit_t win_cnt[0x00020]; /* Number of windows bound to this region. Valid for regions only.
+ The field is valid only for the QUERY_MPT and HW2SW_MPT commands. */
+/* -------------- */
+ pseudo_bit_t reserved5[0x00020];
+/* -------------- */
+ pseudo_bit_t mtt_adr_h[0x00006]; /* Base (first) address of the MTT relative to MTT base in the ICM */
+ pseudo_bit_t reserved6[0x0001a];
+/* -------------- */
+ pseudo_bit_t reserved7[0x00003];
+ pseudo_bit_t mtt_adr_l[0x0001d]; /* Base (first) address of the MTT relative to MTT base address in the ICM. Must be aligned on 8 bytes. */
+/* -------------- */
+ pseudo_bit_t mtt_sz[0x00020]; /* Number of MTT entries allocated for this MR.
+ When Fast Registration Operations can not be executed on this region (FRE bit is zero) this field is reserved.
+ When Fast Registration Operation is enabled (FRE bit is set) this field indicates the number of MTTs allocated for this MR. If mtt_sz value is zero, there is no limit for the numbers of MTTs and the HCA does not check this field when executing fast register WQE. */
+/* -------------- */
+ pseudo_bit_t reserved8[0x00040];
+/* -------------- */
+};
+
+/* Completion Queue Context Table Entry */
+
+struct arbelprm_completion_queue_context_st { /* Little Endian */
+ pseudo_bit_t reserved0[0x00008];
+ pseudo_bit_t st[0x00004]; /* Event delivery state machine
+ 0x0 - reserved
+ 0x9 - ARMED (Request for Notification)
+ 0x6 - ARMED SOLICITED (Request Solicited Notification)
+ 0xA - FIRED
+ other - reserved
+
+ Must be 0x0 in CQ initialization.
+ Valid for the QUERY_CQ and HW2SW_CQ commands only. */
+ pseudo_bit_t reserved1[0x00005];
+ pseudo_bit_t oi[0x00001]; /* When set, overrun ignore is enabled.
+ When set, Updates of CQ consumer counter (poll for completion) or Request completion notifications (Arm CQ) doorbells should not be rang on that CQ. */
+ pseudo_bit_t reserved2[0x0000a];
+ pseudo_bit_t status[0x00004]; /* CQ status
+ 0000 - OK
+ 1001 - CQ overflow
+ 1010 - CQ write failure
+ Valid for the QUERY_CQ and HW2SW_CQ commands only */
+/* -------------- */
+ pseudo_bit_t start_address_h[0x00020];/* Start address of CQ[63:32].
+ Must be aligned on CQE size (32 bytes) */
+/* -------------- */
+ pseudo_bit_t start_address_l[0x00020];/* Start address of CQ[31:0].
+ Must be aligned on CQE size (32 bytes) */
+/* -------------- */
+ pseudo_bit_t usr_page[0x00018]; /* UAR page this CQ can be accessed through (ringinig CQ doorbells) */
+ pseudo_bit_t log_cq_size[0x00005]; /* Log (base 2) of the CQ size (in entries).
+ Maximum CQ size is 2^17 CQEs (max log_cq_size is 17) */
+ pseudo_bit_t reserved3[0x00003];
+/* -------------- */
+ pseudo_bit_t reserved4[0x00020];
+/* -------------- */
+ pseudo_bit_t c_eqn[0x00008]; /* Event Queue this CQ reports completion events to.
+ Valid values are 0 to 63
+ If configured to value other than 0-63, completion events will not be reported on the CQ. */
+ pseudo_bit_t reserved5[0x00018];
+/* -------------- */
+ pseudo_bit_t pd[0x00018]; /* Protection Domain to be used to access CQ.
+ Must be the same PD of the CQ L_Key. */
+ pseudo_bit_t reserved6[0x00008];
+/* -------------- */
+ pseudo_bit_t l_key[0x00020]; /* Memory key (L_Key) to be used to access CQ */
+/* -------------- */
+ pseudo_bit_t last_notified_indx[0x00020];/* Maintained by HW.
+ Valid for QUERY_CQ and HW2SW_CQ commands only. */
+/* -------------- */
+ pseudo_bit_t solicit_producer_indx[0x00020];/* Maintained by HW.
+ Valid for QUERY_CQ and HW2SW_CQ commands only.
+ */
+/* -------------- */
+ pseudo_bit_t consumer_counter[0x00020];/* Consumer counter is a 32bits counter that is incremented for each CQE pooled from the CQ.
+ Must be 0x0 in CQ initialization.
+ Valid for the QUERY_CQ and HW2SW_CQ commands only. */
+/* -------------- */
+ pseudo_bit_t producer_counter[0x00020];/* Producer counter is a 32bits counter that is incremented for each CQE that is written by the HW to the CQ.
+ CQ overrun is reported if Producer_counter + 1 equals to Consumer_counter and a CQE needs to be added..
+ Maintained by HW (valid for the QUERY_CQ and HW2SW_CQ commands only) */
+/* -------------- */
+ pseudo_bit_t cqn[0x00018]; /* CQ number. Least significant bits are constrained by the position of this CQ in CQC table
+ Valid for the QUERY_CQ and HW2SW_CQ commands only */
+ pseudo_bit_t reserved7[0x00008];
+/* -------------- */
+ pseudo_bit_t cq_ci_db_record[0x00020];/* Index in the UAR Context Table Entry.
+ HW uses this index as an offset from the UAR Context Table Entry in order to read this CQ Consumer Counter doorbell record.
+ This value can be retrieved from the HW in the QUERY_CQ command. */
+/* -------------- */
+ pseudo_bit_t cq_state_db_record[0x00020];/* Index in the UAR Context Table Entry.
+ HW uses this index as an offset from the UAR Context Table Entry in order to read this CQ state doorbell record.
+ This value can be retrieved from the HW in the QUERY_CQ command. */
+/* -------------- */
+ pseudo_bit_t reserved8[0x00020];
+/* -------------- */
+};
+
+/* GPIO_event_data */
+
+struct arbelprm_gpio_event_data_st { /* Little Endian */
+ pseudo_bit_t reserved0[0x00060];
+/* -------------- */
+ pseudo_bit_t gpio_event_hi[0x00020];/* If any bit is set to 1, then a rising/falling event has occurred on the corrsponding GPIO pin. */
+/* -------------- */
+ pseudo_bit_t gpio_event_lo[0x00020];/* If any bit is set to 1, then a rising/falling event has occurred on the corrsponding GPIO pin. */
+/* -------------- */
+ pseudo_bit_t reserved1[0x00020];
+/* -------------- */
+};
+
+/* Event_data Field - QP/EE Events */
+
+struct arbelprm_qp_ee_event_st { /* Little Endian */
+ pseudo_bit_t qpn_een[0x00018]; /* QP/EE/SRQ number event is reported for */
+ pseudo_bit_t reserved0[0x00008];
+/* -------------- */
+ pseudo_bit_t reserved1[0x00020];
+/* -------------- */
+ pseudo_bit_t reserved2[0x0001c];
+ pseudo_bit_t e_q[0x00001]; /* If set - EEN if cleared - QP in the QPN/EEN field
+ Not valid on SRQ events */
+ pseudo_bit_t reserved3[0x00003];
+/* -------------- */
+ pseudo_bit_t reserved4[0x00060];
+/* -------------- */
+};
+
+/* InfiniHost-III-EX Type0 Configuration Header */
+
+struct arbelprm_mt25208_type0_st { /* Little Endian */
+ pseudo_bit_t vendor_id[0x00010]; /* Hardwired to 0x15B3 */
+ pseudo_bit_t device_id[0x00010]; /* 25208 (decimal) - InfiniHost-III compatible mode
+ 25218 (decimal) - InfiniHost-III EX mode (the mode described in this manual)
+ 25209 (decimal) - Flash burner mode - see Flash burning application note for further details on this mode
+ */
+/* -------------- */
+ pseudo_bit_t command[0x00010]; /* PCI Command Register */
+ pseudo_bit_t status[0x00010]; /* PCI Status Register */
+/* -------------- */
+ pseudo_bit_t revision_id[0x00008];
+ pseudo_bit_t class_code_hca_class_code[0x00018];
+/* -------------- */
+ pseudo_bit_t cache_line_size[0x00008];/* Cache Line Size */
+ pseudo_bit_t latency_timer[0x00008];
+ pseudo_bit_t header_type[0x00008]; /* hardwired to zero */
+ pseudo_bit_t bist[0x00008];
+/* -------------- */
+ pseudo_bit_t bar0_ctrl[0x00004]; /* hard-wired to 0100 */
+ pseudo_bit_t reserved0[0x00010];
+ pseudo_bit_t bar0_l[0x0000c]; /* Lower bits of BAR0 (Device Configuration Space) */
+/* -------------- */
+ pseudo_bit_t bar0_h[0x00020]; /* Upper 32 bits of BAR0 (Device Configuration Space) */
+/* -------------- */
+ pseudo_bit_t bar1_ctrl[0x00004]; /* Hardwired to 1100 */
+ pseudo_bit_t reserved1[0x00010];
+ pseudo_bit_t bar1_l[0x0000c]; /* Lower bits of BAR1 (User Access Region - UAR - space) */
+/* -------------- */
+ pseudo_bit_t bar1_h[0x00020]; /* upper 32 bits of BAR1 (User Access Region - UAR - space) */
+/* -------------- */
+ pseudo_bit_t bar2_ctrl[0x00004]; /* Hardwired to 1100 */
+ pseudo_bit_t reserved2[0x00010];
+ pseudo_bit_t bar2_l[0x0000c]; /* Lower bits of BAR2 - Local Attached Memory if present and enabled. Else zeroed. */
+/* -------------- */
+ pseudo_bit_t bar2_h[0x00020]; /* Upper 32 bits of BAR2 - Local Attached Memory if present and enabled. Else zeroed. */
+/* -------------- */
+ pseudo_bit_t cardbus_cis_pointer[0x00020];
+/* -------------- */
+ pseudo_bit_t subsystem_vendor_id[0x00010];/* Specified by the device NVMEM configuration */
+ pseudo_bit_t subsystem_id[0x00010]; /* Specified by the device NVMEM configuration */
+/* -------------- */
+ pseudo_bit_t expansion_rom_enable[0x00001];/* Expansion ROM Enable. Hardwired to 0 if expansion ROM is disabled in the device NVMEM configuration. */
+ pseudo_bit_t reserved3[0x0000a];
+ pseudo_bit_t expansion_rom_base_address[0x00015];/* Expansion ROM Base Address (upper 21 bit). Hardwired to 0 if expansion ROM is disabled in the device NVMEM configuration. */
+/* -------------- */
+ pseudo_bit_t capabilities_pointer[0x00008];/* Specified by the device NVMEM configuration */
+ pseudo_bit_t reserved4[0x00018];
+/* -------------- */
+ pseudo_bit_t reserved5[0x00020];
+/* -------------- */
+ pseudo_bit_t interrupt_line[0x00008];
+ pseudo_bit_t interrupt_pin[0x00008];
+ pseudo_bit_t min_gnt[0x00008];
+ pseudo_bit_t max_latency[0x00008];
+/* -------------- */
+ pseudo_bit_t reserved6[0x00100];
+/* -------------- */
+ pseudo_bit_t msi_cap_id[0x00008];
+ pseudo_bit_t msi_next_cap_ptr[0x00008];
+ pseudo_bit_t msi_en[0x00001];
+ pseudo_bit_t multiple_msg_cap[0x00003];
+ pseudo_bit_t multiple_msg_en[0x00003];
+ pseudo_bit_t cap_64_bit_addr[0x00001];
+ pseudo_bit_t reserved7[0x00008];
+/* -------------- */
+ pseudo_bit_t msg_addr_l[0x00020];
+/* -------------- */
+ pseudo_bit_t msg_addr_h[0x00020];
+/* -------------- */
+ pseudo_bit_t msg_data[0x00010];
+ pseudo_bit_t reserved8[0x00010];
+/* -------------- */
+ pseudo_bit_t reserved9[0x00080];
+/* -------------- */
+ pseudo_bit_t pm_cap_id[0x00008]; /* Power management capability ID - 01h */
+ pseudo_bit_t pm_next_cap_ptr[0x00008];
+ pseudo_bit_t pm_cap[0x00010]; /* [2:0] Version - 02h
+ [3] PME clock - 0h
+ [4] RsvP
+ [5] Device specific initialization - 0h
+ [8:6] AUX current - 0h
+ [9] D1 support - 0h
+ [10] D2 support - 0h
+ [15:11] PME support - 0h */
+/* -------------- */
+ pseudo_bit_t pm_status_control[0x00010];/* [14:13] - Data scale - 0h */
+ pseudo_bit_t pm_control_status_brdg_ext[0x00008];
+ pseudo_bit_t data[0x00008];
+/* -------------- */
+ pseudo_bit_t reserved10[0x00040];
+/* -------------- */
+ pseudo_bit_t vpd_cap_id[0x00008]; /* 03h */
+ pseudo_bit_t vpd_next_cap_id[0x00008];
+ pseudo_bit_t vpd_address[0x0000f];
+ pseudo_bit_t f[0x00001];
+/* -------------- */
+ pseudo_bit_t vpd_data[0x00020];
+/* -------------- */
+ pseudo_bit_t reserved11[0x00040];
+/* -------------- */
+ pseudo_bit_t pciex_cap_id[0x00008]; /* PCI-Express capability ID - 10h */
+ pseudo_bit_t pciex_next_cap_ptr[0x00008];
+ pseudo_bit_t pciex_cap[0x00010]; /* [3:0] Capability version - 1h
+ [7:4] Device/Port Type - 0h
+ [8] Slot implemented - 0h
+ [13:9] Interrupt message number
+ */
+/* -------------- */
+ pseudo_bit_t device_cap[0x00020]; /* [2:0] Max_Payload_Size supported - 2h
+ [4:3] Phantom Function supported - 0h
+ [5] Extended Tag Filed supported - 0h
+ [8:6] Endpoint L0s Acceptable Latency - TBD
+ [11:9] Endpoint L1 Acceptable Latency - TBD
+ [12] Attention Button Present - configured through InfiniBurn
+ [13] Attention Indicator Present - configured through InfiniBurn
+ [14] Power Indicator Present - configured through InfiniBurn
+ [25:18] Captured Slot Power Limit Value
+ [27:26] Captured Slot Power Limit Scale */
+/* -------------- */
+ pseudo_bit_t device_control[0x00010];
+ pseudo_bit_t device_status[0x00010];
+/* -------------- */
+ pseudo_bit_t link_cap[0x00020]; /* [3:0] Maximum Link Speed - 1h
+ [9:4] Maximum Link Width - 8h
+ [11:10] Active State Power Management Support - 3h
+ [14:12] L0s Exit Latency - TBD
+ [17:15] L1 Exit Latency - TBD
+ [31:24] Port Number - 0h */
+/* -------------- */
+ pseudo_bit_t link_control[0x00010];
+ pseudo_bit_t link_status[0x00010]; /* [3:0] Link Speed - 1h
+ [9:4] Negotiated Link Width
+ [12] Slot clock configuration - 1h */
+/* -------------- */
+ pseudo_bit_t reserved12[0x00260];
+/* -------------- */
+ pseudo_bit_t advanced_error_reporting_cap_id[0x00010];/* 0001h. */
+ pseudo_bit_t capability_version[0x00004];/* 1h */
+ pseudo_bit_t next_capability_offset[0x0000c];/* 0h */
+/* -------------- */
+ pseudo_bit_t uncorrectable_error_status_register[0x00020];/* 0 Training Error Status
+ 4 Data Link Protocol Error Status
+ 12 Poisoned TLP Status
+ 13 Flow Control Protocol Error Status
+ 14 Completion Timeout Status
+ 15 Completer Abort Status
+ 16 Unexpected Completion Status
+ 17 Receiver Overflow Status
+ 18 Malformed TLP Status
+ 19 ECRC Error Status
+ 20 Unsupported Request Error Status */
+/* -------------- */
+ pseudo_bit_t uncorrectable_error_mask_register[0x00020];/* 0 Training Error Mask
+ 4 Data Link Protocol Error Mask
+ 12 Poisoned TLP Mask
+ 13 Flow Control Protocol Error Mask
+ 14 Completion Timeout Mask
+ 15 Completer Abort Mask
+ 16 Unexpected Completion Mask
+ 17 Receiver Overflow Mask
+ 18 Malformed TLP Mask
+ 19 ECRC Error Mask
+ 20 Unsupported Request Error Mask */
+/* -------------- */
+ pseudo_bit_t uncorrectable_severity_mask_register[0x00020];/* 0 Training Error Severity
+ 4 Data Link Protocol Error Severity
+ 12 Poisoned TLP Severity
+ 13 Flow Control Protocol Error Severity
+ 14 Completion Timeout Severity
+ 15 Completer Abort Severity
+ 16 Unexpected Completion Severity
+ 17 Receiver Overflow Severity
+ 18 Malformed TLP Severity
+ 19 ECRC Error Severity
+ 20 Unsupported Request Error Severity */
+/* -------------- */
+ pseudo_bit_t correctable_error_status_register[0x00020];/* 0 Receiver Error Status
+ 6 Bad TLP Status
+ 7 Bad DLLP Status
+ 8 REPLAY_NUM Rollover Status
+ 12 Replay Timer Timeout Status */
+/* -------------- */
+ pseudo_bit_t correctable_error_mask_register[0x00020];/* 0 Receiver Error Mask
+ 6 Bad TLP Mask
+ 7 Bad DLLP Mask
+ 8 REPLAY_NUM Rollover Mask
+ 12 Replay Timer Timeout Mask */
+/* -------------- */
+ pseudo_bit_t advance_error_capabilities_and_control_register[0x00020];
+/* -------------- */
+ struct arbelprm_header_log_register_st header_log_register;
+/* -------------- */
+ pseudo_bit_t reserved13[0x006a0];
+/* -------------- */
+};
+
+/* Event Data Field - Performance Monitor */
+
+struct arbelprm_performance_monitor_event_st { /* Little Endian */
+ struct arbelprm_performance_monitors_st performance_monitor_snapshot;/* Performance monitor snapshot */
+/* -------------- */
+ pseudo_bit_t monitor_number[0x00008];/* 0x01 - SQPC
+ 0x02 - RQPC
+ 0x03 - CQC
+ 0x04 - Rkey
+ 0x05 - TLB
+ 0x06 - port0
+ 0x07 - port1 */
+ pseudo_bit_t reserved0[0x00018];
+/* -------------- */
+ pseudo_bit_t reserved1[0x00040];
+/* -------------- */
+};
+
+/* Event_data Field - Page Faults */
+
+struct arbelprm_page_fault_event_data_st { /* Little Endian */
+ pseudo_bit_t va_h[0x00020]; /* Virtual Address[63:32] this page fault is reported on */
+/* -------------- */
+ pseudo_bit_t va_l[0x00020]; /* Virtual Address[63:32] this page fault is reported on */
+/* -------------- */
+ pseudo_bit_t mem_key[0x00020]; /* Memory Key this page fault is reported on */
+/* -------------- */
+ pseudo_bit_t qp[0x00018]; /* QP this page fault is reported on */
+ pseudo_bit_t reserved0[0x00003];
+ pseudo_bit_t a[0x00001]; /* If set the memory access that caused the page fault was atomic */
+ pseudo_bit_t lw[0x00001]; /* If set the memory access that caused the page fault was local write */
+ pseudo_bit_t lr[0x00001]; /* If set the memory access that caused the page fault was local read */
+ pseudo_bit_t rw[0x00001]; /* If set the memory access that caused the page fault was remote write */
+ pseudo_bit_t rr[0x00001]; /* If set the memory access that caused the page fault was remote read */
+/* -------------- */
+ pseudo_bit_t pd[0x00018]; /* PD this page fault is reported on */
+ pseudo_bit_t reserved1[0x00008];
+/* -------------- */
+ pseudo_bit_t prefetch_len[0x00020]; /* Indicates how many subsequent pages in the same memory region/window will be accessed by the following transaction after this page fault is resolved. measured in bytes. SW can use this information in order to page-in the subsequent pages if they are not present. */
+/* -------------- */
+};
+
+/* WQE segments format */
+
+struct arbelprm_wqe_segment_st { /* Little Endian */
+ struct arbelprm_send_wqe_segment_st send_wqe_segment;/* Send WQE segment format */
+/* -------------- */
+ pseudo_bit_t reserved0[0x00280];
+/* -------------- */
+ struct arbelprm_wqe_segment_ctrl_mlx_st mlx_wqe_segment_ctrl;/* MLX WQE segment format */
+/* -------------- */
+ pseudo_bit_t reserved1[0x00100];
+/* -------------- */
+ struct arbelprm_wqe_segment_ctrl_recv_st recv_wqe_segment_ctrl;/* Receive segment format */
+/* -------------- */
+ pseudo_bit_t reserved2[0x00080];
+/* -------------- */
+};
+
+/* Event_data Field - Port State Change */
+
+struct arbelprm_port_state_change_st { /* Little Endian */
+ pseudo_bit_t reserved0[0x00040];
+/* -------------- */
+ pseudo_bit_t reserved1[0x0001c];
+ pseudo_bit_t p[0x00002]; /* Port number (1 or 2) */
+ pseudo_bit_t reserved2[0x00002];
+/* -------------- */
+ pseudo_bit_t reserved3[0x00060];
+/* -------------- */
+};
+
+/* Event_data Field - Completion Queue Error */
+
+struct arbelprm_completion_queue_error_st { /* Little Endian */
+ pseudo_bit_t cqn[0x00018]; /* CQ number event is reported for */
+ pseudo_bit_t reserved0[0x00008];
+/* -------------- */
+ pseudo_bit_t reserved1[0x00020];
+/* -------------- */
+ pseudo_bit_t syndrome[0x00008]; /* Error syndrome
+ 0x01 - CQ overrun
+ 0x02 - CQ access violation error */
+ pseudo_bit_t reserved2[0x00018];
+/* -------------- */
+ pseudo_bit_t reserved3[0x00060];
+/* -------------- */
+};
+
+/* Event_data Field - Completion Event */
+
+struct arbelprm_completion_event_st { /* Little Endian */
+ pseudo_bit_t cqn[0x00018]; /* CQ number event is reported for */
+ pseudo_bit_t reserved0[0x00008];
+/* -------------- */
+ pseudo_bit_t reserved1[0x000a0];
+/* -------------- */
+};
+
+/* Event Queue Entry */
+
+struct arbelprm_event_queue_entry_st { /* Little Endian */
+ pseudo_bit_t event_sub_type[0x00008];/* Event Sub Type.
+ Defined for events which have sub types, zero elsewhere. */
+ pseudo_bit_t reserved0[0x00008];
+ pseudo_bit_t event_type[0x00008]; /* Event Type */
+ pseudo_bit_t reserved1[0x00008];
+/* -------------- */
+ pseudo_bit_t event_data[6][0x00020];/* Delivers auxilary data to handle event. */
+/* -------------- */
+ pseudo_bit_t reserved2[0x00007];
+ pseudo_bit_t owner[0x00001]; /* Owner of the entry
+ 0 SW
+ 1 HW */
+ pseudo_bit_t reserved3[0x00018];
+/* -------------- */
+};
+
+/* QP/EE State Transitions Command Parameters */
+
+struct arbelprm_qp_ee_state_transitions_st { /* Little Endian */
+ pseudo_bit_t opt_param_mask[0x00020];/* This field defines which optional parameters are passed. Each bit specifies whether optional parameter is passed (set) or not (cleared). The optparammask is defined for each QP/EE command. */
+/* -------------- */
+ pseudo_bit_t reserved0[0x00020];
+/* -------------- */
+ struct arbelprm_queue_pair_ee_context_entry_st qpc_eec_data;/* QPC/EEC data */
+/* -------------- */
+ pseudo_bit_t reserved1[0x009c0];
+/* -------------- */
+};
+
+/* Completion Queue Entry Format */
+
+struct arbelprm_completion_queue_entry_st { /* Little Endian */
+ pseudo_bit_t my_qpn[0x00018]; /* Indicates the QP for which completion is being reported */
+ pseudo_bit_t reserved0[0x00004];
+ pseudo_bit_t ver[0x00004]; /* CQE version.
+ 0 for InfiniHost-III-EX */
+/* -------------- */
+ pseudo_bit_t my_ee[0x00018]; /* EE context (for RD only).
+ Invalid for Bind and Nop operation on RD.
+ For non RD services this filed reports the CQE timestamp. The Timestamp is a free running counter that is incremented every TimeStampGranularity tick. The counter rolls-over when it reaches saturation. TimeStampGranularity is configured in the INIT_HCA command. This feature is currently not supported.
+ */
+ pseudo_bit_t checksum_15_8[0x00008];/* Checksum[15:8] - See IPoverIB checksum offloading chapter */
+/* -------------- */
+ pseudo_bit_t rqpn[0x00018]; /* Remote (source) QP number. Valid in Responder CQE only for Datagram QP. */
+ pseudo_bit_t checksum_7_0[0x00008]; /* Checksum[7:0] - See IPoverIB checksum offloading chapter */
+/* -------------- */
+ pseudo_bit_t rlid[0x00010]; /* Remote (source) LID of the message. Valid in Responder of UD QP CQE only. */
+ pseudo_bit_t ml_path[0x00007]; /* My (destination) LID path bits - these are the lowemost LMC bits of the DLID in an incoming UD packet, higher bits of this field, that are not part of the LMC bits are zeroed by HW.
+ Valid in responder of UD QP CQE only.
+ Invalid if incoming message DLID is the permissive LID or incoming message is multicast. */
+ pseudo_bit_t g[0x00001]; /* GRH present indicator. Valid in Responder of UD QP CQE only. */
+ pseudo_bit_t ipok[0x00001]; /* IP OK - See IPoverIB checksum offloading chapter */
+ pseudo_bit_t reserved1[0x00003];
+ pseudo_bit_t sl[0x00004]; /* Service Level of the message. Valid in Responder of UD QP CQE only. */
+/* -------------- */
+ pseudo_bit_t immediate_ethertype_pkey_indx_eecredits[0x00020];/* Valid for receive queue completion only.
+ If Opcode field indicates that this was send/write with immediate, this field contains immediate field of the packet.
+ If completion corresponds to RAW receive queue, bits 15:0 contain Ethertype field of the packet.
+ If completion corresponds to GSI receive queue, bits 31:16 contain index in PKey table that matches PKey of the message arrived.
+ If Opcode field indicates that this was send and invalidate, this field contains the key that was invalidated.
+ For CQE of send queue of the reliable connection service (but send and invalide), bits [4:0] of this field contain the encoded EEcredits received in last ACK of the message. */
+/* -------------- */
+ pseudo_bit_t byte_cnt[0x00020]; /* Byte count of data actually transferred (valid for receive queue completions only) */
+/* -------------- */
+ pseudo_bit_t reserved2[0x00006];
+ pseudo_bit_t wqe_adr[0x0001a]; /* Bits 31:6 of WQE virtual address completion is reported for. The 6 least significant bits are zero. */
+/* -------------- */
+ pseudo_bit_t reserved3[0x00007];
+ pseudo_bit_t owner[0x00001]; /* Owner field. Zero value of this field means SW ownership of CQE. */
+ pseudo_bit_t reserved4[0x0000f];
+ pseudo_bit_t s[0x00001]; /* If set, completion is reported for Send queue, if cleared - receive queue. */
+ pseudo_bit_t opcode[0x00008]; /* The opcode of WQE completion is reported for.
+ For CQEs corresponding to send completion, NOPCODE field of the WQE is copied to this field.
+ For CQEs corresponding to receive completions, opcode field of last packet in the message copied to this field.
+ For CQEs corresponding to the receive queue of QPs mapped to QP1, the opcode will be SEND with Immediate (messages are guaranteed to be SEND only)
+
+ The following values are reported in case of completion with error:
+ 0xFE - For completion with error on Receive Queues
+ 0xFF - For completion with error on Send Queues */
+/* -------------- */
+};
+
+/* */
+
+struct arbelprm_ecc_detect_event_data_st { /* Little Endian */
+ pseudo_bit_t reserved0[0x00080];
+/* -------------- */
+ pseudo_bit_t cause_lsb[0x00001];
+ pseudo_bit_t reserved1[0x00002];
+ pseudo_bit_t cause_msb[0x00001];
+ pseudo_bit_t reserved2[0x00002];
+ pseudo_bit_t err_rmw[0x00001];
+ pseudo_bit_t err_src_id[0x00003];
+ pseudo_bit_t err_da[0x00002];
+ pseudo_bit_t err_ba[0x00002];
+ pseudo_bit_t reserved3[0x00011];
+ pseudo_bit_t overflow[0x00001];
+/* -------------- */
+ pseudo_bit_t err_ra[0x00010];
+ pseudo_bit_t err_ca[0x00010];
+/* -------------- */
+};
+
+/* Event_data Field - ECC Detection Event */
+
+struct arbelprm_scrubbing_event_st { /* Little Endian */
+ pseudo_bit_t reserved0[0x00080];
+/* -------------- */
+ pseudo_bit_t cause_lsb[0x00001]; /* data integrity error cause:
+ single ECC error in the 64bit lsb data, on the rise edge of the clock */
+ pseudo_bit_t reserved1[0x00002];
+ pseudo_bit_t cause_msb[0x00001]; /* data integrity error cause:
+ single ECC error in the 64bit msb data, on the fall edge of the clock */
+ pseudo_bit_t reserved2[0x00002];
+ pseudo_bit_t err_rmw[0x00001]; /* transaction type:
+ 0 - read
+ 1 - read/modify/write */
+ pseudo_bit_t err_src_id[0x00003]; /* source of the transaction: 0x4 - PCI, other - internal or IB */
+ pseudo_bit_t err_da[0x00002]; /* Error DIMM address */
+ pseudo_bit_t err_ba[0x00002]; /* Error bank address */
+ pseudo_bit_t reserved3[0x00011];
+ pseudo_bit_t overflow[0x00001]; /* Fatal: ECC error FIFO overflow - ECC errors were detected, which may or may not have been corrected by InfiniHost-III-EX */
+/* -------------- */
+ pseudo_bit_t err_ra[0x00010]; /* Error row address */
+ pseudo_bit_t err_ca[0x00010]; /* Error column address */
+/* -------------- */
+};
+
+/* Miscellaneous Counters */
+
+struct arbelprm_misc_counters_st { /* Little Endian */
+ pseudo_bit_t ddr_scan_cnt[0x00020]; /* Number of times whole of LAM was scanned */
+/* -------------- */
+ pseudo_bit_t reserved0[0x007e0];
+/* -------------- */
+};
+
+/* LAM_EN Output Parameter */
+
+struct arbelprm_lam_en_out_param_st { /* Little Endian */
+ pseudo_bit_t reserved0[0x00040];
+/* -------------- */
+};
+
+/* Extended_Completion_Queue_Entry */
+
+struct arbelprm_extended_completion_queue_entry_st { /* Little Endian */
+ pseudo_bit_t reserved0[0x00020];
+/* -------------- */
+};
+
+/* */
+
+struct arbelprm_eq_cmd_doorbell_st { /* Little Endian */
+ pseudo_bit_t reserved0[0x00020];
+/* -------------- */
+};
+
+/* 0 */
+
+struct arbelprm_arbel_prm_st { /* Little Endian */
+ struct arbelprm_completion_queue_entry_st completion_queue_entry;/* Completion Queue Entry Format */
+/* -------------- */
+ pseudo_bit_t reserved0[0x7ff00];
+/* -------------- */
+ struct arbelprm_qp_ee_state_transitions_st qp_ee_state_transitions;/* QP/EE State Transitions Command Parameters */
+/* -------------- */
+ pseudo_bit_t reserved1[0x7f000];
+/* -------------- */
+ struct arbelprm_event_queue_entry_st event_queue_entry;/* Event Queue Entry */
+/* -------------- */
+ pseudo_bit_t reserved2[0x7ff00];
+/* -------------- */
+ struct arbelprm_completion_event_st completion_event;/* Event_data Field - Completion Event */
+/* -------------- */
+ pseudo_bit_t reserved3[0x7ff40];
+/* -------------- */
+ struct arbelprm_completion_queue_error_st completion_queue_error;/* Event_data Field - Completion Queue Error */
+/* -------------- */
+ pseudo_bit_t reserved4[0x7ff40];
+/* -------------- */
+ struct arbelprm_port_state_change_st port_state_change;/* Event_data Field - Port State Change */
+/* -------------- */
+ pseudo_bit_t reserved5[0x7ff40];
+/* -------------- */
+ struct arbelprm_wqe_segment_st wqe_segment;/* WQE segments format */
+/* -------------- */
+ pseudo_bit_t reserved6[0x7f000];
+/* -------------- */
+ struct arbelprm_page_fault_event_data_st page_fault_event_data;/* Event_data Field - Page Faults */
+/* -------------- */
+ pseudo_bit_t reserved7[0x7ff40];
+/* -------------- */
+ struct arbelprm_performance_monitor_event_st performance_monitor_event;/* Event Data Field - Performance Monitor */
+/* -------------- */
+ pseudo_bit_t reserved8[0xfff20];
+/* -------------- */
+ struct arbelprm_mt25208_type0_st mt25208_type0;/* InfiniHost-III-EX Type0 Configuration Header */
+/* -------------- */
+ pseudo_bit_t reserved9[0x7f000];
+/* -------------- */
+ struct arbelprm_qp_ee_event_st qp_ee_event;/* Event_data Field - QP/EE Events */
+/* -------------- */
+ pseudo_bit_t reserved10[0x00040];
+/* -------------- */
+ struct arbelprm_gpio_event_data_st gpio_event_data;
+/* -------------- */
+ pseudo_bit_t reserved11[0x7fe40];
+/* -------------- */
+ struct arbelprm_ud_address_vector_st ud_address_vector;/* UD Address Vector */
+/* -------------- */
+ pseudo_bit_t reserved12[0x7ff00];
+/* -------------- */
+ struct arbelprm_queue_pair_ee_context_entry_st queue_pair_ee_context_entry;/* QP and EE Context Entry */
+/* -------------- */
+ pseudo_bit_t reserved13[0x7fa00];
+/* -------------- */
+ struct arbelprm_address_path_st address_path;/* Address Path */
+/* -------------- */
+ pseudo_bit_t reserved14[0x7ff00];
+/* -------------- */
+ struct arbelprm_completion_queue_context_st completion_queue_context;/* Completion Queue Context Table Entry */
+/* -------------- */
+ pseudo_bit_t reserved15[0x7fe00];
+/* -------------- */
+ struct arbelprm_mpt_st mpt; /* Memory Protection Table (MPT) Entry */
+/* -------------- */
+ pseudo_bit_t reserved16[0x7fe00];
+/* -------------- */
+ struct arbelprm_mtt_st mtt; /* Memory Translation Table (MTT) Entry */
+/* -------------- */
+ pseudo_bit_t reserved17[0x7ffc0];
+/* -------------- */
+ struct arbelprm_eqc_st eqc; /* Event Queue Context Table Entry */
+/* -------------- */
+ pseudo_bit_t reserved18[0x7fe00];
+/* -------------- */
+ struct arbelprm_performance_monitors_st performance_monitors;/* Performance Monitors */
+/* -------------- */
+ pseudo_bit_t reserved19[0x7ff80];
+/* -------------- */
+ struct arbelprm_hca_command_register_st hca_command_register;/* HCA Command Register (HCR) */
+/* -------------- */
+ pseudo_bit_t reserved20[0xfff20];
+/* -------------- */
+ struct arbelprm_init_hca_st init_hca;/* INIT_HCA & QUERY_HCA Parameters Block */
+/* -------------- */
+ pseudo_bit_t reserved21[0x7f000];
+/* -------------- */
+ struct arbelprm_qpcbaseaddr_st qpcbaseaddr;/* QPC/EEC/CQC/EQC/RDB Parameters */
+/* -------------- */
+ pseudo_bit_t reserved22[0x7fc00];
+/* -------------- */
+ struct arbelprm_udavtable_memory_parameters_st udavtable_memory_parameters;/* Memory Access Parameters for UD Address Vector Table */
+/* -------------- */
+ pseudo_bit_t reserved23[0x7ffc0];
+/* -------------- */
+ struct arbelprm_multicastparam_st multicastparam;/* Multicast Support Parameters */
+/* -------------- */
+ pseudo_bit_t reserved24[0x7ff00];
+/* -------------- */
+ struct arbelprm_tptparams_st tptparams;/* Translation and Protection Tables Parameters */
+/* -------------- */
+ pseudo_bit_t reserved25[0x7ff00];
+/* -------------- */
+ struct arbelprm_enable_lam_st enable_lam;/* ENABLE_LAM Parameters Block */
+/* -------------- */
+ struct arbelprm_access_lam_st access_lam;
+/* -------------- */
+ pseudo_bit_t reserved26[0x7f700];
+/* -------------- */
+ struct arbelprm_dimminfo_st dimminfo;/* Logical DIMM Information */
+/* -------------- */
+ pseudo_bit_t reserved27[0x7ff00];
+/* -------------- */
+ struct arbelprm_query_fw_st query_fw;/* QUERY_FW Parameters Block */
+/* -------------- */
+ pseudo_bit_t reserved28[0x7f800];
+/* -------------- */
+ struct arbelprm_query_adapter_st query_adapter;/* QUERY_ADAPTER Parameters Block */
+/* -------------- */
+ pseudo_bit_t reserved29[0x7f800];
+/* -------------- */
+ struct arbelprm_query_dev_lim_st query_dev_lim;/* Query Device Limitations */
+/* -------------- */
+ pseudo_bit_t reserved30[0x7f800];
+/* -------------- */
+ struct arbelprm_uar_params_st uar_params;/* UAR Parameters */
+/* -------------- */
+ pseudo_bit_t reserved31[0x7ff00];
+/* -------------- */
+ struct arbelprm_init_ib_st init_ib; /* INIT_IB Parameters */
+/* -------------- */
+ pseudo_bit_t reserved32[0x7f800];
+/* -------------- */
+ struct arbelprm_mgm_entry_st mgm_entry;/* Multicast Group Member */
+/* -------------- */
+ pseudo_bit_t reserved33[0x7fe00];
+/* -------------- */
+ struct arbelprm_set_ib_st set_ib; /* SET_IB Parameters */
+/* -------------- */
+ pseudo_bit_t reserved34[0x7fe00];
+/* -------------- */
+ struct arbelprm_rd_send_doorbell_st rd_send_doorbell;/* RD-send doorbell */
+/* -------------- */
+ pseudo_bit_t reserved35[0x7ff80];
+/* -------------- */
+ struct arbelprm_send_doorbell_st send_doorbell;/* Send doorbell */
+/* -------------- */
+ pseudo_bit_t reserved36[0x7ffc0];
+/* -------------- */
+ struct arbelprm_receive_doorbell_st receive_doorbell;/* Receive doorbell */
+/* -------------- */
+ pseudo_bit_t reserved37[0x7ffc0];
+/* -------------- */
+ struct arbelprm_cq_cmd_doorbell_st cq_cmd_doorbell;/* CQ Doorbell */
+/* -------------- */
+ pseudo_bit_t reserved38[0xfffc0];
+/* -------------- */
+ struct arbelprm_uar_st uar; /* User Access Region */
+/* -------------- */
+ pseudo_bit_t reserved39[0x7c000];
+/* -------------- */
+ struct arbelprm_mgmqp_st mgmqp; /* Multicast Group Member QP */
+/* -------------- */
+ pseudo_bit_t reserved40[0x7ffe0];
+/* -------------- */
+ struct arbelprm_query_debug_msg_st query_debug_msg;/* Query Debug Message */
+/* -------------- */
+ pseudo_bit_t reserved41[0x7f800];
+/* -------------- */
+ struct arbelprm_mad_ifc_st mad_ifc; /* MAD_IFC Input Mailbox */
+/* -------------- */
+ pseudo_bit_t reserved42[0x00900];
+/* -------------- */
+ struct arbelprm_mad_ifc_input_modifier_st mad_ifc_input_modifier;/* MAD_IFC Input Modifier */
+/* -------------- */
+ pseudo_bit_t reserved43[0x7e6e0];
+/* -------------- */
+ struct arbelprm_resize_cq_st resize_cq;/* Resize CQ Input Mailbox */
+/* -------------- */
+ pseudo_bit_t reserved44[0x7fe00];
+/* -------------- */
+ struct arbelprm_completion_with_error_st completion_with_error;/* Completion with Error CQE */
+/* -------------- */
+ pseudo_bit_t reserved45[0x7ff00];
+/* -------------- */
+ struct arbelprm_hcr_completion_event_st hcr_completion_event;/* Event_data Field - HCR Completion Event */
+/* -------------- */
+ pseudo_bit_t reserved46[0x7ff40];
+/* -------------- */
+ struct arbelprm_transport_and_ci_error_counters_st transport_and_ci_error_counters;/* Transport and CI Error Counters */
+/* -------------- */
+ pseudo_bit_t reserved47[0x7f000];
+/* -------------- */
+ struct arbelprm_performance_counters_st performance_counters;/* Performance Counters */
+/* -------------- */
+ pseudo_bit_t reserved48[0x9ff800];
+/* -------------- */
+ struct arbelprm_fast_registration_segment_st fast_registration_segment;/* Fast Registration Segment */
+/* -------------- */
+ pseudo_bit_t reserved49[0x7ff00];
+/* -------------- */
+ struct arbelprm_pbl_st pbl; /* Physical Buffer List */
+/* -------------- */
+ pseudo_bit_t reserved50[0x7ff00];
+/* -------------- */
+ struct arbelprm_srq_context_st srq_context;/* SRQ Context */
+/* -------------- */
+ pseudo_bit_t reserved51[0x7fe80];
+/* -------------- */
+ struct arbelprm_mod_stat_cfg_st mod_stat_cfg;/* MOD_STAT_CFG */
+/* -------------- */
+ pseudo_bit_t reserved52[0x7f800];
+/* -------------- */
+ struct arbelprm_virtual_physical_mapping_st virtual_physical_mapping;/* Virtual and Physical Mapping */
+/* -------------- */
+ pseudo_bit_t reserved53[0x7ff80];
+/* -------------- */
+ struct arbelprm_cq_ci_db_record_st cq_ci_db_record;/* CQ_CI_DB_Record */
+/* -------------- */
+ pseudo_bit_t reserved54[0x7ffc0];
+/* -------------- */
+ struct arbelprm_cq_arm_db_record_st cq_arm_db_record;/* CQ_ARM_DB_Record */
+/* -------------- */
+ pseudo_bit_t reserved55[0x7ffc0];
+/* -------------- */
+ struct arbelprm_qp_db_record_st qp_db_record;/* QP_DB_Record */
+/* -------------- */
+ pseudo_bit_t reserved56[0x1fffc0];
+/* -------------- */
+ struct arbelprm_configuration_registers_st configuration_registers;/* InfiniHost III EX Configuration Registers */
+/* -------------- */
+ struct arbelprm_eq_set_ci_table_st eq_set_ci_table;/* EQ Set CI DBs Table */
+/* -------------- */
+ pseudo_bit_t reserved57[0x01000];
+/* -------------- */
+ struct arbelprm_eq_arm_db_region_st eq_arm_db_region;/* EQ Arm Doorbell Region */
+/* -------------- */
+ pseudo_bit_t reserved58[0x00fc0];
+/* -------------- */
+ struct arbelprm_clr_int_st clr_int; /* Clear Interrupt Register */
+/* -------------- */
+ pseudo_bit_t reserved59[0xffcfc0];
+/* -------------- */
+};
+#endif /* H_prefix_arbelprm_bits_fixnames_MT25218_PRM_csp_H */
diff --git a/src/drivers/net/mlx_ipoib/bit_ops.h b/src/drivers/net/mlx_ipoib/bit_ops.h
new file mode 100644
index 000000000..e3fb4331f
--- /dev/null
+++ b/src/drivers/net/mlx_ipoib/bit_ops.h
@@ -0,0 +1,126 @@
+/*
+ This software is available to you under a choice of one of two
+ licenses. You may choose to be licensed under the terms of the GNU
+ General Public License (GPL) Version 2, available at
+ <http://www.fsf.org/copyleft/gpl.html>, or the OpenIB.org BSD
+ license, available in the LICENSE.TXT file accompanying this
+ software. These details are also available at
+ <http://openib.org/license.html>.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+
+ Copyright (c) 2004 Mellanox Technologies Ltd. All rights reserved.
+*/
+
+#ifndef __bit_ops_h__
+#define __bit_ops_h__
+
+typedef unsigned long MT_offset_t;
+typedef unsigned long MT_size_t;
+typedef unsigned char pseudo_bit_t;
+struct addr_64_st {
+ __u32 addr_l;
+ __u32 addr_h;
+};
+
+#define MT_BIT_OFFSET(object_struct,reg_path) \
+ ((MT_offset_t) &( ((struct object_struct *)(0))-> reg_path ))
+
+#define MT_BIT_SIZE(object_struct,reg_path) \
+ ((MT_size_t) sizeof( ((struct object_struct *)(0))-> reg_path ))
+
+#define MT_BIT_OFFSET_SIZE(object_struct,reg_path) \
+ MT_BIT_OFFSET(object_struct,reg_path),MT_BIT_SIZE(object_struct,reg_path)
+
+#define MT_BYTE_OFFSET(object_struct,reg_path) \
+ ((MT_offset_t) (MT_BIT_OFFSET(object_struct,reg_path)/8))
+
+#define MT_BYTE_SIZE(object_struct,reg_path) \
+ ((MT_size_t) MT_BIT_SIZE(object_struct,reg_path)/8)
+
+#define MT_BYTE_OFFSET_SIZE(object_struct,reg_path) \
+ MT_BYTE_OFFSET(object_struct,reg_path),MT_BYTE_SIZE(object_struct,reg_path)
+
+#define MT_STRUCT_SIZE(object_struct) (sizeof(struct object_struct) >> 3)
+
+/*****************************************************************************************
+ * Bit manipulation macros
+ *****************************************************************************************/
+
+/* MASK generate a bit mask S bits width */
+#define MASK32(S) ( ((__u32) ~0L) >> (32-(S)) )
+
+/*
+ * BITS generate a bit mask with bits O+S..O set (assumes 32 bit integer).
+ * numbering bits as following: 31........................76543210
+ */
+#define BITS32(O,S) ( MASK32(S) << (O) )
+
+/*
+ * MT_EXTRACT32 macro extracts S bits from (__u32)W with offset O
+ * and shifts them O places to the right (right justifies the field extracted).
+ */
+#define MT_EXTRACT32(W,O,S) ( ((W)>>(O)) & MASK32(S) )
+
+/*
+ * MT_INSERT32 macro inserts S bits with offset O from field F into word W (__u32)
+ */
+#define MT_INSERT32(W,F,O,S) ((W)= ( ( (W) & (~BITS32(O,S)) ) | (((F) & MASK32(S))<<(O)) ))
+
+/*
+ * MT_EXTRACT_ARRAY32 macro is similar to EXTRACT but works on an array of (__u32),
+ * thus offset may be larger than 32 (but not size).
+ */
+#define MT_EXTRACT_ARRAY32(A,O,S) MT_EXTRACT32(((__u32*)A)[O >> 5],(O & MASK32(5)),S)
+
+/*
+ * MT_INSERT_ARRAY32 macro is similar to INSERT but works on an array of (__u32),
+ * thus offset may be larger than 32 (but not size).
+ */
+#define MT_INSERT_ARRAY32(A,F,O,S) MT_INSERT32(((__u32*)A)[O >> 5],F,(O & MASK32(5)),S)
+
+#define INS_FLD(src, a, st, fld) MT_INSERT_ARRAY32(a, src, MT_BIT_OFFSET(st, fld), MT_BIT_SIZE(st, fld))
+
+#define EX_FLD(a, st, fld) MT_EXTRACT_ARRAY32(a, MT_BIT_OFFSET(st, fld), MT_BIT_SIZE(st, fld))
+
+/* return the address of the dword holding the field
+
+ buf = pointer to buffer where to place the value
+ st = struct describing the buffer
+ fld = field in the struct where to insert the value */
+
+#define FLD_DW_ADDR(buf, st, fld) ((__u32 *)((__u32 *)(buf)+(((__u32)(&(((struct st *)(0))->fld))) >> 5)))
+
+/*
+ val = value to insert
+ buf = pointer to buffer where to place the value
+ st = struct describing the buffer
+ fld = field in the struct where to insert the value */
+
+#define INS_FLD_TO_BE(val, buf, st, fld) \
+ do { \
+ *FLD_DW_ADDR(buf, st, fld) = be32_to_cpu(*FLD_DW_ADDR(buf, st, fld)); \
+ INS_FLD(val, buf, st, fld); \
+ *FLD_DW_ADDR(buf, st, fld) = cpu_to_be32(*FLD_DW_ADDR(buf, st, fld)); \
+ } \
+ while(0)
+
+#define EX_FLD_FROM_BE(buf, st, fld, type) \
+({ \
+ type field; \
+ \
+ *FLD_DW_ADDR(buf, st, fld) = be32_to_cpu(*FLD_DW_ADDR(buf, st, fld)); \
+ field= EX_FLD(buf, st, fld); \
+ *FLD_DW_ADDR(buf, st, fld) = cpu_to_be32(*FLD_DW_ADDR(buf, st, fld)); \
+ \
+ field; \
+})
+
+#endif /* __bit_ops_h__ */
diff --git a/src/drivers/net/mlx_ipoib/cmdif.h b/src/drivers/net/mlx_ipoib/cmdif.h
new file mode 100644
index 000000000..375a60f2b
--- /dev/null
+++ b/src/drivers/net/mlx_ipoib/cmdif.h
@@ -0,0 +1,50 @@
+/*
+ This software is available to you under a choice of one of two
+ licenses. You may choose to be licensed under the terms of the GNU
+ General Public License (GPL) Version 2, available at
+ <http://www.fsf.org/copyleft/gpl.html>, or the OpenIB.org BSD
+ license, available in the LICENSE.TXT file accompanying this
+ software. These details are also available at
+ <http://openib.org/license.html>.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+
+ Copyright (c) 2004 Mellanox Technologies Ltd. All rights reserved.
+*/
+
+#ifndef __cmdif_h_
+#define __cmdif_h_
+
+#include "ib_mad.h"
+
+static int cmd_init_hca(__u32 * inprm, __u32 in_prm_size);
+static int cmd_close_hca(int panic);
+static int cmd_sw2hw_eq(__u32 inprm_sz);
+static int cmd_hw2sw_eq(__u8 eqn);
+static int cmd_map_eq(__u8 eqn, __u32 mask, int map);
+static int cmd_sw2hw_mpt(__u32 * lkey, __u32 in_key, __u32 * inprm,
+ __u32 inprm_sz);
+static int cmd_hw2sw_mpt(__u32 key);
+static int cmd_init_ib(__u32 port, __u32 * inprm, __u32 inprm_sz);
+static int cmd_close_ib(__u32 port);
+static int cmd_sw2hw_cq(__u32 cqn, __u32 * inprm, __u32 inprm_sz);
+static int cmd_hw2sw_cq(__u32 cqn);
+static int cmd_rst2init_qpee(__u32 qpn, __u32 * inprm, __u32 inprm_sz);
+static int cmd_init2rtr_qpee(__u32 qpn, __u32 * inprm, __u32 inprm_sz);
+static int cmd_rtr2rts_qpee(__u32 qpn, __u32 * inprm, __u32 inprm_sz);
+static int cmd_2rst_qpee(__u32 qpn);
+static int cmd_2err_qpee(__u32 qpn);
+static int cmd_post_doorbell(void *inprm, __u32 offset);
+static int cmd_mad_ifc(void *inprm, struct ib_mad_st *mad, __u8 port);
+static int cmd_write_mgm( /*struct mg_member_layout_st */ void *mg,
+ __u16 index);
+static int cmd_mgid_hash(__u8 * gid, __u16 * mgid_hash_p);
+
+#endif /* __cmdif_h_ */
diff --git a/src/drivers/net/mlx_ipoib/cmdif_comm.c b/src/drivers/net/mlx_ipoib/cmdif_comm.c
new file mode 100644
index 000000000..d43a1068b
--- /dev/null
+++ b/src/drivers/net/mlx_ipoib/cmdif_comm.c
@@ -0,0 +1,564 @@
+/*
+ This software is available to you under a choice of one of two
+ licenses. You may choose to be licensed under the terms of the GNU
+ General Public License (GPL) Version 2, available at
+ <http://www.fsf.org/copyleft/gpl.html>, or the OpenIB.org BSD
+ license, available in the LICENSE.TXT file accompanying this
+ software. These details are also available at
+ <http://openib.org/license.html>.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+
+ Copyright (c) 2004 Mellanox Technologies Ltd. All rights reserved.
+*/
+
+#include "cmdif.h"
+#include "cmdif_comm.h"
+#include "cmdif_priv.h"
+
+static int cmdif_is_free(int *is_free)
+{
+ int rc;
+ __u32 result;
+
+ rc = gw_read_cr(HCR_OFFSET_GO, &result);
+ if (rc) {
+ eprintf("");
+ return rc;
+ }
+ *is_free = (result & 0x800000) == 0;
+
+ return 0;
+}
+
+static void edit_hcr(command_fields_t * cmd_prms, __u32 * buf)
+{
+ unsigned int i;
+
+ switch (cmd_prms->in_trans) {
+ case TRANS_NA:
+ /* note! since these are zeroes I do not bother to deal with endianess */
+ buf[0] = 0;
+ buf[1] = 0;
+ break;
+
+ case TRANS_IMMEDIATE:
+ buf[0] = cmd_prms->in_param[0];
+ buf[1] = cmd_prms->in_param[1];
+ break;
+
+ case TRANS_MAILBOX:
+ buf[0] = 0;
+ buf[1] = virt_to_bus(cmd_prms->in_param);
+
+ for (i = 0; i < cmd_prms->in_param_size; i += 4)
+ cmd_prms->in_param[i >> 2] =
+ cpu_to_be32(cmd_prms->in_param[i >> 2]);
+ break;
+ }
+
+ buf[2] = cmd_prms->input_modifier;
+
+ switch (cmd_prms->out_trans) {
+ case TRANS_NA:
+ /* note! since these are zeroes I do not bother to deal with endianess */
+ buf[3] = 0;
+ buf[4] = 0;
+ break;
+
+ case TRANS_IMMEDIATE:
+ break;
+ case TRANS_MAILBOX:
+ buf[3] = 0;
+ buf[4] = virt_to_bus(cmd_prms->out_param);
+ break;
+ }
+
+ buf[5] = 0; /* token is always 0 */
+ buf[6] = cmd_prms->opcode | /* opcode */
+ 0x800000 | /* go bit */
+ ((cmd_prms->opcode_modifier & 0xf) << 12); /* opcode modifier
+*/ }
+
+static int wait_cmdif_free(void)
+{
+ int ret, is_free;
+ unsigned int i, relax_time = 1, max_time = 5000;
+
+ /* wait until go bit is free */
+ for (i = 0; i < max_time; i += relax_time) {
+ ret = cmdif_is_free(&is_free);
+ if (ret)
+ return ret;
+ if (is_free)
+ break;
+ mdelay(relax_time);
+ }
+ if (i >= max_time)
+ return -1;
+ return 0;
+}
+
+static XHH_cmd_status_t cmd_invoke(command_fields_t * cmd_prms)
+{
+ int ret, is_free, i;
+ __u32 hcr[7], data;
+ __u8 status;
+
+ /* check if go bit is free */
+ ret = cmdif_is_free(&is_free);
+ if (ret) {
+ eprintf("");
+ return -1;
+ }
+
+ __asm__ __volatile__("":::"memory");
+ /* it must be free */
+ if (!is_free) {
+ eprintf("");
+ return -1;
+ }
+ __asm__ __volatile__("":::"memory");
+ edit_hcr(cmd_prms, hcr);
+ __asm__ __volatile__("":::"memory");
+
+ for (i = 0; i < 7; ++i) {
+ ret = gw_write_cr(HCR_BASE + i * 4, hcr[i]);
+ if (ret) {
+ eprintf("");
+ return -1;
+ }
+ }
+
+ __asm__ __volatile__("":::"memory");
+ /* wait for completion */
+ ret = wait_cmdif_free();
+ if (ret) {
+ eprintf("");
+ return -1;
+ }
+
+ __asm__ __volatile__("":::"memory");
+ ret = gw_read_cr(HCR_OFFSET_STATUS, &data);
+ if (ret) {
+ eprintf("");
+ return -1;
+ }
+
+ status = data >> 24;
+
+ if (status) {
+ tprintf("status=0x%x", status);
+ return status;
+ }
+
+ if (cmd_prms->out_trans == TRANS_MAILBOX)
+ be_to_cpu_buf(cmd_prms->out_param, cmd_prms->out_param_size);
+ else if (cmd_prms->out_trans == TRANS_IMMEDIATE) {
+ if (gw_read_cr(HCR_OFFSET_OUTPRM_H, &cmd_prms->out_param[0]))
+ return -1;
+ if (gw_read_cr(HCR_OFFSET_OUTPRM_L, &cmd_prms->out_param[1]))
+ return -1;
+ }
+
+ return 0;
+}
+
+/*************************************************
+ commands
+*************************************************/
+
+/*
+ * cmd_close_hca
+ */
+static int cmd_close_hca(int panic)
+{
+ int rc;
+ command_fields_t cmd_desc;
+
+ memset(&cmd_desc, 0, sizeof cmd_desc);
+ cmd_desc.opcode = XDEV_CMD_CLOSE_HCA;
+ cmd_desc.opcode_modifier= panic;
+ rc = cmd_invoke(&cmd_desc);
+
+ return rc;
+}
+
+/*
+ * cmd_init_hca
+ */
+static int cmd_init_hca(__u32 * inprm, __u32 in_prm_size)
+{
+ int rc;
+
+ command_fields_t cmd_desc;
+
+ memset(&cmd_desc, 0, sizeof cmd_desc);
+ cmd_desc.in_trans = TRANS_MAILBOX;
+ cmd_desc.opcode = XDEV_CMD_INIT_HCA;
+ cmd_desc.in_param = inprm;
+ cmd_desc.in_param_size = in_prm_size;
+
+ rc = cmd_invoke(&cmd_desc);
+
+ return rc;
+}
+
+/*
+ * cmd_sw2hw_eq
+ */
+static int cmd_sw2hw_eq(__u32 inprm_sz)
+{
+ int rc;
+ command_fields_t cmd_desc;
+ void *inprm;
+
+ memset(&cmd_desc, 0, sizeof cmd_desc);
+
+ inprm = get_inprm_buf();
+ cmd_desc.in_trans = TRANS_MAILBOX;
+ cmd_desc.opcode = XDEV_CMD_SW2HW_EQ;
+ cmd_desc.in_param = inprm;
+ cmd_desc.in_param_size = inprm_sz;
+
+ rc = cmd_invoke(&cmd_desc);
+
+ return rc;
+}
+
+/*
+ * cmd_hw2sw_eq
+ */
+static int cmd_hw2sw_eq(__u8 eqn)
+{
+ int rc;
+ command_fields_t cmd_desc;
+ void *outprm;
+
+ memset(&cmd_desc, 0, sizeof cmd_desc);
+
+ outprm = get_outprm_buf();
+ cmd_desc.opcode = XDEV_CMD_HW2SW_EQ;
+ cmd_desc.input_modifier = eqn;
+ cmd_desc.out_trans = TRANS_MAILBOX;
+ cmd_desc.out_param = outprm;
+ cmd_desc.out_param_size = 0x40;
+ rc = cmd_invoke(&cmd_desc);
+
+ return rc;
+}
+
+/*
+ * cmd_map_eq
+ */
+static int cmd_map_eq(__u8 eqn, __u32 mask, int map)
+{
+ int rc;
+ command_fields_t cmd_desc;
+ __u32 *inprm;
+
+ memset(&cmd_desc, 0, sizeof cmd_desc);
+
+ inprm = get_inprm_buf();
+
+ inprm[1] = mask;
+ inprm[0] = 0;
+
+ cmd_desc.opcode = XDEV_CMD_MAP_EQ;
+ cmd_desc.in_trans = TRANS_IMMEDIATE;
+ cmd_desc.in_param = inprm;
+ cmd_desc.input_modifier = ((map ? 0 : 1) << 31) | eqn;
+
+ rc = cmd_invoke(&cmd_desc);
+
+ return rc;
+}
+
+/*
+ * cmd_sw2hw_mpt
+ */
+static int cmd_sw2hw_mpt(__u32 * lkey, __u32 in_key, __u32 * inprm,
+ __u32 inprm_sz)
+{
+ int rc;
+ command_fields_t cmd_desc;
+
+ memset(&cmd_desc, 0, sizeof cmd_desc);
+ cmd_desc.in_trans = TRANS_MAILBOX;
+ cmd_desc.opcode = XDEV_CMD_SW2HW_MPT;
+ cmd_desc.input_modifier = in_key & MKEY_IDX_MASK; /* only one MR for the whole driver */
+ cmd_desc.in_param = inprm;
+ cmd_desc.in_param_size = inprm_sz;
+
+ rc = cmd_invoke(&cmd_desc);
+ if (!rc)
+ *lkey = in_key;
+
+ return rc;
+}
+
+/*
+ * cmd_hw2sw_mpt
+ */
+static int cmd_hw2sw_mpt(__u32 key)
+{
+ int rc;
+ command_fields_t cmd_desc;
+
+ memset(&cmd_desc, 0, sizeof cmd_desc);
+ cmd_desc.opcode = XDEV_CMD_HW2SW_MPT;
+ cmd_desc.input_modifier = key & MKEY_IDX_MASK;
+ cmd_desc.opcode_modifier = 1;
+
+ rc = cmd_invoke(&cmd_desc);
+
+ return rc;
+}
+
+/*
+ * cmd_init_ib
+ */
+static int cmd_init_ib(__u32 port, __u32 * inprm, __u32 inprm_sz)
+{
+ int rc;
+ command_fields_t cmd_desc;
+
+ memset(&cmd_desc, 0, sizeof cmd_desc);
+ cmd_desc.opcode = XDEV_CMD_INIT_IB;
+ cmd_desc.input_modifier = port;
+ cmd_desc.in_trans = TRANS_MAILBOX;
+ cmd_desc.in_param = inprm;
+ cmd_desc.in_param_size = inprm_sz;
+
+ rc = cmd_invoke(&cmd_desc);
+
+ return rc;
+}
+
+/*
+ * cmd_close_ib
+ */
+static int cmd_close_ib(__u32 port)
+{
+ int rc;
+ command_fields_t cmd_desc;
+
+ memset(&cmd_desc, 0, sizeof cmd_desc);
+ cmd_desc.opcode = XDEV_CMD_CLOSE_IB;
+ cmd_desc.input_modifier = port;
+
+ rc = cmd_invoke(&cmd_desc);
+
+ return rc;
+}
+
+/*
+ * cmd_sw2hw_cq
+ */
+static int cmd_sw2hw_cq(__u32 cqn, __u32 * inprm, __u32 inprm_sz)
+{
+ int rc;
+ command_fields_t cmd_desc;
+
+ memset(&cmd_desc, 0, sizeof cmd_desc);
+ cmd_desc.opcode = XDEV_CMD_SW2HW_CQ;
+ cmd_desc.in_trans = TRANS_MAILBOX;
+ cmd_desc.in_param = inprm;
+ cmd_desc.in_param_size = inprm_sz;
+ cmd_desc.input_modifier = cqn;
+
+ rc = cmd_invoke(&cmd_desc);
+
+ return rc;
+}
+
+/*
+ * cmd_hw2sw_cq
+ */
+static int cmd_hw2sw_cq(__u32 cqn)
+{
+ int rc;
+ command_fields_t cmd_desc;
+
+ memset(&cmd_desc, 0, sizeof cmd_desc);
+ cmd_desc.opcode = XDEV_CMD_HW2SW_CQ;
+ cmd_desc.input_modifier = cqn;
+ cmd_desc.out_trans = TRANS_MAILBOX;
+ cmd_desc.out_param = get_outprm_buf();
+
+ rc = cmd_invoke(&cmd_desc);
+
+ return rc;
+}
+
+/*
+ * cmd_rst2init_qpee
+ */
+static int cmd_rst2init_qpee(__u32 qpn, __u32 * inprm, __u32 inprm_sz)
+{
+ int rc;
+ command_fields_t cmd_desc;
+
+ memset(&cmd_desc, 0, sizeof cmd_desc);
+ cmd_desc.opcode = XDEV_CMD_RST2INIT_QPEE;
+ cmd_desc.in_trans = TRANS_MAILBOX;
+ cmd_desc.in_param = inprm;
+ cmd_desc.in_param_size = inprm_sz;
+ cmd_desc.input_modifier = qpn;
+
+ rc = cmd_invoke(&cmd_desc);
+
+ return rc;
+}
+
+/*
+ * cmd_init2rtr_qpee
+ */
+static int cmd_init2rtr_qpee(__u32 qpn, __u32 * inprm, __u32 inprm_sz)
+{
+ int rc;
+ command_fields_t cmd_desc;
+
+ memset(&cmd_desc, 0, sizeof cmd_desc);
+ cmd_desc.opcode = XDEV_CMD_INIT2RTR_QPEE;
+ cmd_desc.in_trans = TRANS_MAILBOX;
+ cmd_desc.in_param = inprm;
+ cmd_desc.in_param_size = inprm_sz;
+ cmd_desc.input_modifier = qpn;;
+
+ rc = cmd_invoke(&cmd_desc);
+
+ return rc;
+}
+
+/*
+ * cmd_rtr2rts_qpee
+ */
+static int cmd_rtr2rts_qpee(__u32 qpn, __u32 * inprm, __u32 inprm_sz)
+{
+ int rc;
+ command_fields_t cmd_desc;
+
+ memset(&cmd_desc, 0, sizeof cmd_desc);
+ cmd_desc.opcode = XDEV_CMD_RTR2RTS_QPEE;
+ cmd_desc.in_trans = TRANS_MAILBOX;
+ cmd_desc.in_param = inprm;
+ cmd_desc.in_param_size = inprm_sz;
+ cmd_desc.input_modifier = qpn;
+
+ rc = cmd_invoke(&cmd_desc);
+
+ return rc;
+}
+
+/*
+ * cmd_2rst_qpee
+ */
+static int cmd_2rst_qpee(__u32 qpn)
+{
+ int rc;
+ command_fields_t cmd_desc;
+
+ memset(&cmd_desc, 0, sizeof cmd_desc);
+ cmd_desc.opcode = XDEV_CMD_ERR2RST_QPEE;
+ cmd_desc.opcode_modifier = 0;
+ cmd_desc.input_modifier = qpn;
+ cmd_desc.out_trans = TRANS_MAILBOX;
+ cmd_desc.out_param = get_outprm_buf();
+
+ rc = cmd_invoke(&cmd_desc);
+
+ return rc;
+}
+
+/*
+ * cmd_2err_qpee
+ */
+static int cmd_2err_qpee(__u32 qpn)
+{
+ int rc;
+ command_fields_t cmd_desc;
+
+ memset(&cmd_desc, 0, sizeof cmd_desc);
+ cmd_desc.opcode = XDEV_CMD_2ERR_QPEE;
+ cmd_desc.input_modifier = qpn;
+
+ rc = cmd_invoke(&cmd_desc);
+
+ return rc;
+}
+
+/*
+ * cmd_post_doorbell
+ */
+static int cmd_post_doorbell(void *inprm, __u32 offset)
+{
+ int rc;
+ command_fields_t cmd_desc;
+
+ memset(&cmd_desc, 0, sizeof cmd_desc);
+ cmd_desc.opcode = XDEV_CMD_POST_DOORBELL;
+ cmd_desc.in_trans = TRANS_IMMEDIATE;
+ cmd_desc.in_param = inprm;
+ cmd_desc.input_modifier = offset;
+ if (0) {
+ rc = cmd_invoke(&cmd_desc);
+ } else {
+ dev_post_dbell(inprm, offset);
+ rc = 0;
+ }
+
+ return rc;
+}
+
+static int cmd_mad_ifc(void *inprm, struct ib_mad_st *mad, __u8 port)
+{
+ int rc;
+ command_fields_t cmd_desc;
+
+ memset(&cmd_desc, 0, sizeof cmd_desc);
+ cmd_desc.opcode = XDEV_CMD_MAD_IFC;
+ cmd_desc.opcode_modifier = 1; /* no mkey/bkey validation */
+ cmd_desc.input_modifier = port;
+ cmd_desc.in_trans = TRANS_MAILBOX;
+ cmd_desc.in_param_size = 256;
+ cmd_desc.in_param = (__u32 *) inprm;
+ cmd_desc.out_trans = TRANS_MAILBOX;
+ cmd_desc.out_param = (__u32 *) mad;
+ cmd_desc.out_param_size = 256;
+ rc = cmd_invoke(&cmd_desc);
+
+ return rc;
+}
+
+static int cmd_mgid_hash(__u8 * gid, __u16 * mgid_hash_p)
+{
+ int rc;
+ command_fields_t cmd_desc;
+ __u16 result[2];
+
+ memset(&cmd_desc, 0, sizeof cmd_desc);
+
+ cmd_desc.opcode = XDEV_CMD_MGID_HASH;
+ cmd_desc.in_trans = TRANS_MAILBOX;
+ cmd_desc.in_param = (__u32 *) gid;
+ cmd_desc.in_param_size = 16;
+ cmd_desc.out_trans = TRANS_IMMEDIATE;
+
+ rc = cmd_invoke(&cmd_desc);
+ if (!rc) {
+ rc = gw_read_cr(HCR_BASE + 16, (__u32 *) result);
+ if (!rc) {
+ *mgid_hash_p = result[0];
+ }
+ }
+
+ return rc;
+}
diff --git a/src/drivers/net/mlx_ipoib/cmdif_comm.h b/src/drivers/net/mlx_ipoib/cmdif_comm.h
new file mode 100644
index 000000000..e0624fa53
--- /dev/null
+++ b/src/drivers/net/mlx_ipoib/cmdif_comm.h
@@ -0,0 +1,60 @@
+/*
+ This software is available to you under a choice of one of two
+ licenses. You may choose to be licensed under the terms of the GNU
+ General Public License (GPL) Version 2, available at
+ <http://www.fsf.org/copyleft/gpl.html>, or the OpenIB.org BSD
+ license, available in the LICENSE.TXT file accompanying this
+ software. These details are also available at
+ <http://openib.org/license.html>.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+
+ Copyright (c) 2004 Mellanox Technologies Ltd. All rights reserved.
+*/
+
+#ifndef __cmdif_comm_h__
+#define __cmdif_comm_h__
+
+ /* initialization and general commands */
+#define XDEV_CMD_INIT_HCA 0x7
+#define XDEV_CMD_CLOSE_HCA 0x8
+#define XDEV_CMD_INIT_IB 0x9
+#define XDEV_CMD_CLOSE_IB 0xa
+
+ /* TPT commands */
+#define XDEV_CMD_SW2HW_MPT 0xd
+#define XDEV_CMD_HW2SW_MPT 0xf
+
+ /* EQ commands */
+#define XDEV_CMD_MAP_EQ 0x12
+#define XDEV_CMD_SW2HW_EQ 0x13
+#define XDEV_CMD_HW2SW_EQ 0x14
+
+ /* CQ commands */
+#define XDEV_CMD_SW2HW_CQ 0x16
+#define XDEV_CMD_HW2SW_CQ 0x17
+
+ /* QP/EE commands */
+#define XDEV_CMD_RST2INIT_QPEE 0x19
+#define XDEV_CMD_INIT2RTR_QPEE 0x1a
+#define XDEV_CMD_RTR2RTS_QPEE 0x1b
+#define XDEV_CMD_2ERR_QPEE 0x1e
+#define XDEV_CMD_ERR2RST_QPEE 0x21
+
+ /* special QPs and management commands */
+#define XDEV_CMD_MAD_IFC 0x24
+
+ /* multicast commands */
+#define XDEV_CMD_READ_MGM 0x25
+#define XDEV_CMD_MGID_HASH 0x27
+
+#define XDEV_CMD_POST_DOORBELL 0x41
+
+#endif /* __cmdif_comm_h__ */
diff --git a/src/drivers/net/mlx_ipoib/cmdif_mt23108.c b/src/drivers/net/mlx_ipoib/cmdif_mt23108.c
new file mode 100644
index 000000000..7a8f6d601
--- /dev/null
+++ b/src/drivers/net/mlx_ipoib/cmdif_mt23108.c
@@ -0,0 +1,193 @@
+/*
+ This software is available to you under a choice of one of two
+ licenses. You may choose to be licensed under the terms of the GNU
+ General Public License (GPL) Version 2, available at
+ <http://www.fsf.org/copyleft/gpl.html>, or the OpenIB.org BSD
+ license, available in the LICENSE.TXT file accompanying this
+ software. These details are also available at
+ <http://openib.org/license.html>.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+
+ Copyright (c) 2004 Mellanox Technologies Ltd. All rights reserved.
+*/
+#include "cmdif.h"
+#include "cmdif_priv.h"
+#include "mt23108.h"
+
+/*
+ * cmd_sys_en
+ */
+static int cmd_sys_en(void)
+{
+ int rc;
+ command_fields_t cmd_desc;
+
+ memset(&cmd_desc, 0, sizeof cmd_desc);
+ cmd_desc.opcode = TAVOR_CMD_SYS_EN;
+ rc = cmd_invoke(&cmd_desc);
+
+ return rc;
+}
+
+/*
+ * cmd_sys_dis
+ */
+static int cmd_sys_dis(void)
+{
+ int rc;
+ command_fields_t cmd_desc;
+
+ memset(&cmd_desc, 0, sizeof cmd_desc);
+ cmd_desc.in_trans = TRANS_NA;
+ cmd_desc.out_trans = TRANS_NA;
+ cmd_desc.opcode = TAVOR_CMD_SYS_DIS;
+ rc = cmd_invoke(&cmd_desc);
+
+ return rc;
+}
+
+/*
+ * cmd_query_dev_lim
+ */
+static int cmd_query_dev_lim(struct dev_lim_st *dev_lim_p)
+{
+ int rc;
+ command_fields_t cmd_desc;
+
+ memset(&cmd_desc, 0, sizeof cmd_desc);
+
+ cmd_desc.opcode = TAVOR_CMD_QUERY_DEV_LIM;
+ cmd_desc.out_trans = TRANS_MAILBOX;
+ cmd_desc.out_param = get_outprm_buf();
+ cmd_desc.out_param_size = MT_STRUCT_SIZE(tavorprm_query_dev_lim_st);
+
+ rc = cmd_invoke(&cmd_desc);
+ if (!rc) {
+ dev_lim_p->log2_rsvd_qps =
+ EX_FLD(cmd_desc.out_param, tavorprm_query_dev_lim_st,
+ log2_rsvd_qps);
+ dev_lim_p->qpc_entry_sz =
+ EX_FLD(cmd_desc.out_param, tavorprm_query_dev_lim_st,
+ qpc_entry_sz);
+
+ dev_lim_p->log2_rsvd_srqs =
+ EX_FLD(cmd_desc.out_param, tavorprm_query_dev_lim_st,
+ log2_rsvd_srqs);
+ dev_lim_p->srq_entry_sz =
+ EX_FLD(cmd_desc.out_param, tavorprm_query_dev_lim_st,
+ srq_entry_sz);
+
+ dev_lim_p->log2_rsvd_ees =
+ EX_FLD(cmd_desc.out_param, tavorprm_query_dev_lim_st,
+ log2_rsvd_ees);
+ dev_lim_p->eec_entry_sz =
+ EX_FLD(cmd_desc.out_param, tavorprm_query_dev_lim_st,
+ eec_entry_sz);
+
+ dev_lim_p->log2_rsvd_cqs =
+ EX_FLD(cmd_desc.out_param, tavorprm_query_dev_lim_st,
+ log2_rsvd_cqs);
+ dev_lim_p->cqc_entry_sz =
+ EX_FLD(cmd_desc.out_param, tavorprm_query_dev_lim_st,
+ cqc_entry_sz);
+
+ dev_lim_p->log2_rsvd_mtts =
+ EX_FLD(cmd_desc.out_param, tavorprm_query_dev_lim_st,
+ log2_rsvd_mtts);
+ dev_lim_p->mtt_entry_sz = 64; /* segment size is set to zero in init_hca */
+
+ dev_lim_p->log2_rsvd_mrws =
+ EX_FLD(cmd_desc.out_param, tavorprm_query_dev_lim_st,
+ log2_rsvd_mrws);
+ dev_lim_p->mpt_entry_sz = MT_STRUCT_SIZE(tavorprm_mpt_st);
+
+ dev_lim_p->eqc_entry_sz =
+ EX_FLD(cmd_desc.out_param, tavorprm_query_dev_lim_st,
+ eqc_entry_sz);
+ }
+
+ return rc;
+}
+
+/*
+ * cmd_write_mgm
+ */
+static int cmd_write_mgm(void *mg, __u16 index)
+{
+ int rc;
+ command_fields_t cmd_desc;
+
+ memset(&cmd_desc, 0, sizeof cmd_desc);
+ cmd_desc.opcode = TAVOR_CMD_WRITE_MGM;
+ cmd_desc.in_trans = TRANS_MAILBOX;
+ cmd_desc.in_param_size = MT_STRUCT_SIZE(tavorprm_mgm_entry_st);
+ cmd_desc.in_param = (__u32 *) mg;
+ cmd_desc.input_modifier = index;
+
+ rc = cmd_invoke(&cmd_desc);
+
+ return rc;
+}
+
+/*
+ * cmd_mod_stat_cfg
+ */
+static int cmd_mod_stat_cfg(void *cfg)
+{
+ int rc;
+ command_fields_t cmd_desc;
+
+ memset(&cmd_desc, 0, sizeof cmd_desc);
+ cmd_desc.opcode = TAVOR_CMD_MOD_STAT_CFG;
+ cmd_desc.in_trans = TRANS_MAILBOX;
+ cmd_desc.in_param_size = MT_STRUCT_SIZE(tavorprm_mod_stat_cfg_st);
+ cmd_desc.in_param = (__u32 *) cfg;
+
+ rc = cmd_invoke(&cmd_desc);
+
+ return rc;
+}
+
+
+/*
+ * cmd_query_fw
+ */
+static int cmd_query_fw(struct query_fw_st *qfw)
+{
+ int rc;
+ command_fields_t cmd_desc;
+
+ memset(&cmd_desc, 0, sizeof cmd_desc);
+
+ cmd_desc.opcode = TAVOR_CMD_QUERY_FW;
+ cmd_desc.out_trans = TRANS_MAILBOX;
+ cmd_desc.out_param = get_outprm_buf();
+ cmd_desc.out_param_size = MT_STRUCT_SIZE(tavorprm_query_fw_st);
+
+ rc = cmd_invoke(&cmd_desc);
+ if (!rc) {
+ qfw->fw_rev_major =
+ EX_FLD(cmd_desc.out_param, tavorprm_query_fw_st, fw_rev_major);
+ qfw->fw_rev_minor =
+ EX_FLD(cmd_desc.out_param, tavorprm_query_fw_st, fw_rev_minor);
+ qfw->fw_rev_subminor =
+ EX_FLD(cmd_desc.out_param, tavorprm_query_fw_st, fw_rev_subminor);
+
+ qfw->error_buf_start_h =
+ EX_FLD(cmd_desc.out_param, tavorprm_query_fw_st, error_buf_start_h);
+ qfw->error_buf_start_l =
+ EX_FLD(cmd_desc.out_param, tavorprm_query_fw_st, error_buf_start_l);
+ qfw->error_buf_size =
+ EX_FLD(cmd_desc.out_param, tavorprm_query_fw_st, error_buf_size);
+ }
+
+ return rc;
+}
diff --git a/src/drivers/net/mlx_ipoib/cmdif_mt25218.c b/src/drivers/net/mlx_ipoib/cmdif_mt25218.c
new file mode 100644
index 000000000..fb95edbe8
--- /dev/null
+++ b/src/drivers/net/mlx_ipoib/cmdif_mt25218.c
@@ -0,0 +1,457 @@
+/*
+ This software is available to you under a choice of one of two
+ licenses. You may choose to be licensed under the terms of the GNU
+ General Public License (GPL) Version 2, available at
+ <http://www.fsf.org/copyleft/gpl.html>, or the OpenIB.org BSD
+ license, available in the LICENSE.TXT file accompanying this
+ software. These details are also available at
+ <http://openib.org/license.html>.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+
+ Copyright (c) 2004 Mellanox Technologies Ltd. All rights reserved.
+*/
+#include "cmdif.h"
+#include "cmdif_priv.h"
+#include "mt25218.h"
+
+/*
+ * cmd_sys_dis
+ */
+static int cmd_sys_dis(void)
+{
+ return 0;
+}
+
+/*
+ * cmd_write_mgm
+ */
+static int cmd_write_mgm(void *mg, __u16 index)
+{
+ int rc;
+ command_fields_t cmd_desc;
+
+ memset(&cmd_desc, 0, sizeof cmd_desc);
+ cmd_desc.opcode = MEMFREE_CMD_WRITE_MGM;
+ cmd_desc.in_trans = TRANS_MAILBOX;
+ cmd_desc.in_param_size = MT_STRUCT_SIZE(arbelprm_mgm_entry_st);
+ cmd_desc.in_param = (__u32 *) mg;
+ cmd_desc.input_modifier = index;
+
+ rc = cmd_invoke(&cmd_desc);
+
+ return rc;
+}
+
+/*
+ * cmd_mod_stat_cfg
+ */
+static int cmd_mod_stat_cfg(void)
+{
+ int rc;
+ command_fields_t cmd_desc;
+
+ memset(&cmd_desc, 0, sizeof cmd_desc);
+ cmd_desc.opcode = MEMFREE_CMD_MOD_STAT_CFG;
+ cmd_desc.in_trans = TRANS_MAILBOX;
+ cmd_desc.in_param_size = MT_STRUCT_SIZE(arbelprm_mod_stat_cfg_st);
+ cmd_desc.in_param = get_inprm_buf();
+ memset(cmd_desc.in_param, 0, cmd_desc.in_param_size);
+
+ rc = cmd_invoke(&cmd_desc);
+
+ return rc;
+}
+
+/*
+ * cmd_query_fw
+ */
+static int cmd_query_fw(struct query_fw_st *qfw)
+{
+ int rc;
+ command_fields_t cmd_desc;
+
+ memset(&cmd_desc, 0, sizeof cmd_desc);
+
+ cmd_desc.opcode = MEMFREE_CMD_QUERY_FW;
+ cmd_desc.out_trans = TRANS_MAILBOX;
+ cmd_desc.out_param = get_outprm_buf();
+ cmd_desc.out_param_size = MT_STRUCT_SIZE(arbelprm_query_fw_st);
+
+ rc = cmd_invoke(&cmd_desc);
+ if (!rc) {
+ qfw->fw_rev_major =
+ EX_FLD(cmd_desc.out_param, arbelprm_query_fw_st, fw_rev_major);
+ qfw->fw_rev_minor =
+ EX_FLD(cmd_desc.out_param, arbelprm_query_fw_st, fw_rev_minor);
+ qfw->fw_rev_subminor =
+ EX_FLD(cmd_desc.out_param, arbelprm_query_fw_st, fw_rev_subminor);
+
+ qfw->error_buf_start_h =
+ EX_FLD(cmd_desc.out_param, arbelprm_query_fw_st, error_buf_start_h);
+ qfw->error_buf_start_l =
+ EX_FLD(cmd_desc.out_param, arbelprm_query_fw_st, error_buf_start_l);
+ qfw->error_buf_size =
+ EX_FLD(cmd_desc.out_param, arbelprm_query_fw_st, error_buf_size);
+
+ qfw->fw_pages =
+ EX_FLD(cmd_desc.out_param, arbelprm_query_fw_st, fw_pages);
+ qfw->eq_ci_table.addr_h =
+ EX_FLD(cmd_desc.out_param, arbelprm_query_fw_st,
+ eq_set_ci_base_addr_h);
+ qfw->eq_ci_table.addr_l =
+ EX_FLD(cmd_desc.out_param, arbelprm_query_fw_st,
+ eq_set_ci_base_addr_l);
+ qfw->clear_int_addr.addr_h =
+ EX_FLD(cmd_desc.out_param, arbelprm_query_fw_st,
+ clr_int_base_addr_h);
+ qfw->clear_int_addr.addr_l =
+ EX_FLD(cmd_desc.out_param, arbelprm_query_fw_st,
+ clr_int_base_addr_l);
+ }
+
+ return rc;
+}
+
+/*
+ * cmd_query_adapter
+ */
+static int cmd_query_adapter(struct query_adapter_st *qa)
+{
+ int rc;
+ command_fields_t cmd_desc;
+
+ memset(&cmd_desc, 0, sizeof cmd_desc);
+
+ cmd_desc.opcode = MEMFREE_CMD_QUERY_ADAPTER;
+ cmd_desc.out_trans = TRANS_MAILBOX;
+ cmd_desc.out_param = get_outprm_buf();
+ cmd_desc.out_param_size = MT_STRUCT_SIZE(arbelprm_query_adapter_st);
+
+ rc = cmd_invoke(&cmd_desc);
+ if (!rc) {
+ qa->intapin =
+ EX_FLD(cmd_desc.out_param, arbelprm_query_adapter_st,
+ intapin);
+ }
+
+ return rc;
+}
+
+/*
+ * cmd_enable_lam
+ */
+static int cmd_enable_lam(void)
+{
+ int rc;
+ command_fields_t cmd_desc;
+
+ memset(&cmd_desc, 0, sizeof cmd_desc);
+
+ cmd_desc.opcode = MEMFREE_CMD_ENABLE_LAM;
+ cmd_desc.opcode_modifier = 1; /* zero locally attached memory */
+ cmd_desc.input_modifier = 0; /* disable fast refresh */
+ cmd_desc.out_trans = TRANS_MAILBOX;
+ cmd_desc.out_param = get_outprm_buf();
+ cmd_desc.out_param_size = MT_STRUCT_SIZE(arbelprm_enable_lam_st);
+
+ rc = cmd_invoke(&cmd_desc);
+ if (rc) {
+ }
+
+ return rc;
+}
+
+/*
+ * cmd_map_fa
+ */
+static int cmd_map_fa(struct map_icm_st *map_fa_p)
+{
+ int rc;
+ command_fields_t cmd_desc;
+ unsigned int in_param_size, i;
+ unsigned long off;
+
+ if (map_fa_p->num_vpm > MAX_VPM_PER_CALL) {
+ return -1;
+ }
+
+ memset(&cmd_desc, 0, sizeof cmd_desc);
+
+ cmd_desc.opcode = MEMFREE_CMD_MAP_FA;
+ cmd_desc.input_modifier = map_fa_p->num_vpm;
+ cmd_desc.in_trans = TRANS_MAILBOX;
+ cmd_desc.in_param = get_inprm_buf();
+ in_param_size =
+ MT_STRUCT_SIZE(arbelprm_virtual_physical_mapping_st) *
+ map_fa_p->num_vpm;
+ cmd_desc.in_param_size = in_param_size;
+ memset(cmd_desc.in_param, 0, in_param_size);
+
+ for (i = 0; i < map_fa_p->num_vpm; ++i) {
+ off = (unsigned long)(cmd_desc.in_param) +
+ MT_STRUCT_SIZE(arbelprm_virtual_physical_mapping_st) * i;
+ INS_FLD(map_fa_p->vpm_arr[i].va_h, off,
+ arbelprm_virtual_physical_mapping_st, va_h);
+ INS_FLD(map_fa_p->vpm_arr[i].va_l >> 12, off,
+ arbelprm_virtual_physical_mapping_st, va_l);
+ INS_FLD(map_fa_p->vpm_arr[i].pa_h, off,
+ arbelprm_virtual_physical_mapping_st, pa_h);
+ INS_FLD(map_fa_p->vpm_arr[i].pa_l >> 12, off,
+ arbelprm_virtual_physical_mapping_st, pa_l);
+ INS_FLD(map_fa_p->vpm_arr[i].log2_size, off,
+ arbelprm_virtual_physical_mapping_st, log2size);
+ }
+
+ rc = cmd_invoke(&cmd_desc);
+
+ return rc;
+}
+
+/*
+ * cmd_unmap_fa
+ */
+static int cmd_unmap_fa(void)
+{
+ int rc;
+ command_fields_t cmd_desc;
+
+ memset(&cmd_desc, 0, sizeof cmd_desc);
+
+ cmd_desc.opcode = MEMFREE_CMD_UNMAP_FA;
+
+ rc = cmd_invoke(&cmd_desc);
+
+ return rc;
+}
+
+/*
+ * cmd_run_fw
+ */
+static int cmd_run_fw(void)
+{
+ int rc;
+ command_fields_t cmd_desc;
+
+ memset(&cmd_desc, 0, sizeof cmd_desc);
+
+ cmd_desc.opcode = MEMFREE_CMD_RUN_FW;
+ rc = cmd_invoke(&cmd_desc);
+
+ return rc;
+}
+
+/*
+ * cmd_set_icm_size
+ */
+static int cmd_set_icm_size(__u32 icm_size, __u32 * aux_pages_p)
+{
+ int rc;
+ command_fields_t cmd_desc;
+ __u32 iprm[2], oprm[2];
+
+ memset(&cmd_desc, 0, sizeof cmd_desc);
+
+ cmd_desc.opcode = MEMFREE_CMD_SET_ICM_SIZE;
+
+ iprm[1] = icm_size;
+ iprm[0] = 0;
+ cmd_desc.in_trans = TRANS_IMMEDIATE;
+ cmd_desc.in_param = iprm;
+ cmd_desc.out_trans = TRANS_IMMEDIATE;
+ cmd_desc.out_param = oprm;
+ rc = cmd_invoke(&cmd_desc);
+ if (!rc) {
+ if (oprm[0]) {
+ /* too many pages required */
+ return -1;
+ }
+ *aux_pages_p = oprm[1];
+ }
+
+ return rc;
+}
+
+/*
+ * cmd_map_icm_aux
+ */
+static int cmd_map_icm_aux(struct map_icm_st *map_icm_aux_p)
+{
+ int rc;
+ command_fields_t cmd_desc;
+ unsigned int in_param_size, i;
+ unsigned long off;
+
+ if (map_icm_aux_p->num_vpm > MAX_VPM_PER_CALL) {
+ return -1;
+ }
+
+ memset(&cmd_desc, 0, sizeof cmd_desc);
+
+ cmd_desc.opcode = MEMFREE_CMD_MAP_ICM_AUX;
+ cmd_desc.input_modifier = map_icm_aux_p->num_vpm;
+ cmd_desc.in_trans = TRANS_MAILBOX;
+ cmd_desc.in_param = get_inprm_buf();
+ in_param_size =
+ MT_STRUCT_SIZE(arbelprm_virtual_physical_mapping_st) *
+ map_icm_aux_p->num_vpm;
+ cmd_desc.in_param_size = in_param_size;
+ memset(cmd_desc.in_param, 0, in_param_size);
+
+ for (i = 0; i < map_icm_aux_p->num_vpm; ++i) {
+ off = (unsigned long)(cmd_desc.in_param) +
+ MT_STRUCT_SIZE(arbelprm_virtual_physical_mapping_st) * i;
+ INS_FLD(map_icm_aux_p->vpm_arr[i].va_h, off,
+ arbelprm_virtual_physical_mapping_st, va_h);
+ INS_FLD(map_icm_aux_p->vpm_arr[i].va_l >> 12, off,
+ arbelprm_virtual_physical_mapping_st, va_l);
+ INS_FLD(map_icm_aux_p->vpm_arr[i].pa_h, off,
+ arbelprm_virtual_physical_mapping_st, pa_h);
+ INS_FLD(map_icm_aux_p->vpm_arr[i].pa_l >> 12, off,
+ arbelprm_virtual_physical_mapping_st, pa_l);
+ INS_FLD(map_icm_aux_p->vpm_arr[i].log2_size, off,
+ arbelprm_virtual_physical_mapping_st, log2size);
+ }
+
+ rc = cmd_invoke(&cmd_desc);
+
+ return rc;
+}
+
+/*
+ * cmd_map_icm
+ */
+static int cmd_map_icm(struct map_icm_st *map_icm_p)
+{
+ int rc;
+ command_fields_t cmd_desc;
+ unsigned int in_param_size, i;
+ unsigned long off;
+
+ if (map_icm_p->num_vpm > MAX_VPM_PER_CALL) {
+ return -1;
+ }
+
+ memset(&cmd_desc, 0, sizeof cmd_desc);
+
+ cmd_desc.opcode = MEMFREE_CMD_MAP_ICM;
+ cmd_desc.input_modifier = map_icm_p->num_vpm;
+ cmd_desc.in_trans = TRANS_MAILBOX;
+ cmd_desc.in_param = get_inprm_buf();
+ in_param_size =
+ MT_STRUCT_SIZE(arbelprm_virtual_physical_mapping_st) *
+ map_icm_p->num_vpm;
+ cmd_desc.in_param_size = in_param_size;
+ memset(cmd_desc.in_param, 0, in_param_size);
+
+ for (i = 0; i < map_icm_p->num_vpm; ++i) {
+ off = (unsigned long)(cmd_desc.in_param) +
+ MT_STRUCT_SIZE(arbelprm_virtual_physical_mapping_st) * i;
+ INS_FLD(map_icm_p->vpm_arr[i].va_h, off,
+ arbelprm_virtual_physical_mapping_st, va_h);
+ INS_FLD(map_icm_p->vpm_arr[i].va_l >> 12, off,
+ arbelprm_virtual_physical_mapping_st, va_l);
+ INS_FLD(map_icm_p->vpm_arr[i].pa_h, off,
+ arbelprm_virtual_physical_mapping_st, pa_h);
+ INS_FLD(map_icm_p->vpm_arr[i].pa_l >> 12, off,
+ arbelprm_virtual_physical_mapping_st, pa_l);
+ INS_FLD(map_icm_p->vpm_arr[i].log2_size, off,
+ arbelprm_virtual_physical_mapping_st, log2size);
+ }
+
+ rc = cmd_invoke(&cmd_desc);
+
+ return rc;
+}
+
+/*
+ * cmd_query_dev_lim
+ */
+static int cmd_query_dev_lim(struct dev_lim_st *dev_lim_p)
+{
+ int rc;
+ command_fields_t cmd_desc;
+
+ memset(&cmd_desc, 0, sizeof cmd_desc);
+
+ cmd_desc.opcode = MEMFREE_CMD_QUERY_DEV_LIM;
+ cmd_desc.out_trans = TRANS_MAILBOX;
+ cmd_desc.out_param = get_outprm_buf();
+ cmd_desc.out_param_size = MT_STRUCT_SIZE(arbelprm_query_dev_lim_st);
+
+ rc = cmd_invoke(&cmd_desc);
+ if (!rc) {
+ dev_lim_p->log2_rsvd_qps =
+ EX_FLD(cmd_desc.out_param, arbelprm_query_dev_lim_st,
+ log2_rsvd_qps);
+ dev_lim_p->qpc_entry_sz =
+ EX_FLD(cmd_desc.out_param, arbelprm_query_dev_lim_st,
+ qpc_entry_sz);
+
+ dev_lim_p->log2_rsvd_srqs =
+ EX_FLD(cmd_desc.out_param, arbelprm_query_dev_lim_st,
+ log2_rsvd_srqs);
+ dev_lim_p->srq_entry_sz =
+ EX_FLD(cmd_desc.out_param, arbelprm_query_dev_lim_st,
+ srq_entry_sz);
+
+ dev_lim_p->log2_rsvd_ees =
+ EX_FLD(cmd_desc.out_param, arbelprm_query_dev_lim_st,
+ log2_rsvd_ees);
+ dev_lim_p->eec_entry_sz =
+ EX_FLD(cmd_desc.out_param, arbelprm_query_dev_lim_st,
+ eec_entry_sz);
+
+ dev_lim_p->log2_rsvd_cqs =
+ EX_FLD(cmd_desc.out_param, arbelprm_query_dev_lim_st,
+ log2_rsvd_cqs);
+ dev_lim_p->cqc_entry_sz =
+ EX_FLD(cmd_desc.out_param, arbelprm_query_dev_lim_st,
+ cqc_entry_sz);
+
+ dev_lim_p->log2_rsvd_mtts =
+ EX_FLD(cmd_desc.out_param, arbelprm_query_dev_lim_st,
+ log2_rsvd_mtts);
+ dev_lim_p->mtt_entry_sz =
+ EX_FLD(cmd_desc.out_param, arbelprm_query_dev_lim_st,
+ mtt_entry_sz);
+
+ dev_lim_p->log2_rsvd_mrws =
+ EX_FLD(cmd_desc.out_param, arbelprm_query_dev_lim_st,
+ log2_rsvd_mrws);
+ dev_lim_p->mpt_entry_sz =
+ EX_FLD(cmd_desc.out_param, arbelprm_query_dev_lim_st,
+ mpt_entry_sz);
+
+ dev_lim_p->log2_rsvd_rdbs =
+ EX_FLD(cmd_desc.out_param, arbelprm_query_dev_lim_st,
+ log2_rsvd_rdbs);
+
+ dev_lim_p->eqc_entry_sz =
+ EX_FLD(cmd_desc.out_param, arbelprm_query_dev_lim_st,
+ eqc_entry_sz);
+
+ dev_lim_p->max_icm_size_l =
+ EX_FLD(cmd_desc.out_param, arbelprm_query_dev_lim_st,
+ max_icm_size_l);
+ dev_lim_p->max_icm_size_h =
+ EX_FLD(cmd_desc.out_param, arbelprm_query_dev_lim_st,
+ max_icm_size_h);
+
+ dev_lim_p->num_rsvd_uars =
+ EX_FLD(cmd_desc.out_param, arbelprm_query_dev_lim_st,
+ num_rsvd_uars);
+ dev_lim_p->uar_sz =
+ EX_FLD(cmd_desc.out_param, arbelprm_query_dev_lim_st,
+ uar_sz);
+ }
+
+ return rc;
+}
diff --git a/src/drivers/net/mlx_ipoib/cmdif_priv.h b/src/drivers/net/mlx_ipoib/cmdif_priv.h
new file mode 100644
index 000000000..dbb9a373e
--- /dev/null
+++ b/src/drivers/net/mlx_ipoib/cmdif_priv.h
@@ -0,0 +1,50 @@
+/*
+ This software is available to you under a choice of one of two
+ licenses. You may choose to be licensed under the terms of the GNU
+ General Public License (GPL) Version 2, available at
+ <http://www.fsf.org/copyleft/gpl.html>, or the OpenIB.org BSD
+ license, available in the LICENSE.TXT file accompanying this
+ software. These details are also available at
+ <http://openib.org/license.html>.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+
+ Copyright (c) 2004 Mellanox Technologies Ltd. All rights reserved.
+*/
+
+#ifndef __cmdif_priv__h__
+#define __cmdif_priv__h__
+
+typedef enum {
+ TRANS_NA,
+ TRANS_IMMEDIATE,
+ TRANS_MAILBOX
+} trans_type_t;
+
+typedef struct {
+ __u32 *in_param; /* holds the virtually contigious buffer of the parameter block passed */
+ unsigned int in_param_size;
+ trans_type_t in_trans;
+
+ __u32 input_modifier;
+
+ __u32 *out_param; /* holds the virtually contigious buffer of the parameter block passed */
+ unsigned int out_param_size;
+ trans_type_t out_trans;
+
+ __u32 opcode;
+ __u8 opcode_modifier;
+} command_fields_t;
+
+typedef int XHH_cmd_status_t;
+
+static XHH_cmd_status_t cmd_invoke(command_fields_t * cmd_prms);
+
+#endif
diff --git a/src/drivers/net/mlx_ipoib/doc/README.boot_over_ib b/src/drivers/net/mlx_ipoib/doc/README.boot_over_ib
new file mode 100644
index 000000000..077386286
--- /dev/null
+++ b/src/drivers/net/mlx_ipoib/doc/README.boot_over_ib
@@ -0,0 +1,176 @@
+.Boot over IB over Mellanox HCAs README - Pre-Alpha release
+==========================================================
+Document #2442, Rev 0.10, December 2005
+
+
+1. General
+-----------
+This README describes the Boot over IB package which enables booting a Linux
+kernel from a remote server using one of the Mellanox Technologies HCA
+devices. The package is based on Etherboot 5.4.1.
+
+The package actually implements a network driver for Etherboot. The wire
+protocol is compliant with IP Over IB
+(see http://www.ietf.org/html.charters/ipoib-charter.html for related
+documents).
+
+Etherboot uses a traditional setup of a DHCP server and a TFTP server to
+perform a remote boot in a similar manner to Ethernet NICs. The binary code is
+exported by the device as an expansion ROM image.
+
+
+2. Supported Devices
+---------------------
+The following Mellanox Technologies HCA devices are supported:
+
+ PCI Device ID Mellanox HCA Device
+ ----------------------------------------------
+ 23108 InfiniHost (P/N MT23108)
+ 25208 InfiniHost III Ex (P/N MT25208) (InfiniHost)
+ 25218 InfiniHost III Ex (P/N MT25208) (MemFree)
+ 25204 InfiniHost III Lx (P/N MT25204)
+
+
+ Note: For devices with more than one IB port, port 1 is used for
+ communications.
+
+
+3. Compiling
+----------------
+From the src directory:
+Run" make bin/<device>.<ext>
+where device can be any of:
+ MT23108
+ MT25218
+ MT25208
+ MT25204
+
+and ext can be rom, zrom etc. (see Etherbot doumentation for more details)
+
+4. Directory Structure
+-----------------------
+All driver files are available under src/drivers/net/mlx_ipoib/. Under this
+directory the following files can be found:
+
+ *** doc - Contains related documents including this file.
+ *** patches - Contains needed patch files.
+ *** samples - Contains sample files.
+ *** . Contains driver source files.
+
+
+5. Burning the Flash Memory
+----------------------------
+The binary code resides in the same Flash device of the device firmware.
+However the binary files are distinct and do not affect each other. Mellanox's
+'mlxburn' tool is available for burning, however, it is not possible to burn
+the expansion ROM image by itself; rather, both the firmware and expansion ROM
+images must be burnt simultaneously.
+
+'mlxburn' is part of the Mellanox Firmware Tools (MFT) package available for
+download from www.mellanox.com under 'Firmware Downloads'.
+
+Example:
+The following command burns a firmware image and an expansion ROM image to an
+InfiniHost Adapter Card (P/N MHX-CE128-T.ini):
+
+ mlxburn -fw fw-23108-a1-rel.mlx -exp_rom MT23108.bin
+ /dev/mst/mt23108_pci_cr0 -conf MHX-CE128-T.ini
+
+*** Important Note: The .ini file must support burning expansion ROMs. For
+example, the following lines must appear in the .ini file. If they do not,
+please add them manually.
+
+[ADAPTER]
+exp_rom_en = true
+
+Mellanox's web site contains firmware binary files with extension .bin.gz.
+These files contain contain EVERYTHING the goes in the flash memory and thus
+are NOT suitable for including the expansion rom image. Therefore, one use the
+files with .mlx extension also available from Mellanox's web site.
+
+
+
+6. Preparing the DHCP Server
+-----------------------------
+DHCP messages over IP Over IB are transmitted as broadcasts. In order to
+distinguish between messages belonging to a certain DHCP session, the messages
+must carry the client identifier option (see ietf documentation referred to
+above). As of November 2005, ISC DHCP servers do not support this feature.
+They are expected to support this at the end of 2005. In order to work this
+out, the appropriate patch must be applied (see patches directory). It has
+been tested on version isc-dhcpd-V3.0.4b2.
+
+The DHCP server must run on a machine which supports IP Over IB. The Mellanox
+IBGD package (gen1 or gen2) can be used to provide this.
+To run the DHCP server from the command line use: dhcpd ib0
+
+7. DHCP Server Configuration File
+----------------------------------
+In order for the DHCP server to provide configuration records for clients, an
+appropriate configuration file dhcpd.conf must be created and put under /etc/.
+A sample configuration file with comments can be found in the samples directory.
+
+
+8. OpenSM
+----------
+To successfully boot over IB, the IB network must contain a Subnet Manager
+which configures the IB network. OpenSM is part of the IBGD distribution and
+can be used to accomplish that. Note that OpenSM may be run on the same host
+running the DHCP server but it is not mandatory.
+
+
+9. TFTP Server
+---------------
+When the DHCP session is completed, the client has the IP address of the TFTP
+server from which it should download the kernel image. This TFTP server must
+run on a machine with InfiniBand support. The client loads first a loader
+image based on PXE API which then loads the kernel image. The image can be
+found in the Linux kernel homepage:
+
+http://www.kernel.org/pub/linux/boot/syslinux/
+
+
+10. BIOS Configuration
+-----------------------
+The expansion ROM image presents itself to the BIOS as a boot device. As a
+result, the BIOS will add it to the list of boot devices. The priority of this
+list can be modified when entering the BIOS setup. The boot over IB image must
+be set first for the BIOS to attempt to use it first.
+
+
+11. Operation
+--------------
+When booting the client, a message appears on the screen describing the device
+found and the revision of the code. The user has 3 seconds to press a key for
+increased functionality:
+'V' will increase verbosity.
+'I' will prinit some information to aid in configuring the DHCP configuration
+ file. In this case the display will hold for 5 seconds to let the user
+ grasp the information.
+
+Note that increasing verbosity will significantly slow boot time and will
+print lots of debug messages to the screen.
+
+
+12. Diskless Machines
+----------------------
+Most often it is required to boot a diskless machine. In these cases the
+kernel mounts its root file system over NFS over one of the interfaces. For
+this to happen on a client with only InfiniBand interfaces, the kernel image
+must be configured accordingly and must include IP Over IB support. This can
+be achieved either by compiling this into the kernel or using initrd images
+that contain IP Over IB support.
+
+
+13. Changing Defaults
+----------------------
+As stated the driver uses port 1 for its communications. To use another port
+edit the file src/drivers/net/ib_driver.h and modify the definition of
+PXE_IB_PORT.
+
+
+14. Installing a package from Mellanox
+--------------------------------------
+When using a package obtained from Mellanox Technologies' web site, the
+directory src/bin will contain the driver binary files. The files have a .bin
+extension and are equivalent to the same files with .zrom extension.
diff --git a/src/drivers/net/mlx_ipoib/ib_driver.c b/src/drivers/net/mlx_ipoib/ib_driver.c
new file mode 100644
index 000000000..a46db7fc2
--- /dev/null
+++ b/src/drivers/net/mlx_ipoib/ib_driver.c
@@ -0,0 +1,342 @@
+/*
+ This software is available to you under a choice of one of two
+ licenses. You may choose to be licensed under the terms of the GNU
+ General Public License (GPL) Version 2, available at
+ <http://www.fsf.org/copyleft/gpl.html>, or the OpenIB.org BSD
+ license, available in the LICENSE.TXT file accompanying this
+ software. These details are also available at
+ <http://openib.org/license.html>.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+
+ Copyright (c) 2004 Mellanox Technologies Ltd. All rights reserved.
+*/
+
+#include "ib_driver.h"
+
+static const __u8 ipv4_bcast_gid[] = {
+ 0xff, 0x12, 0x40, 0x1b, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff
+};
+
+static int wait_logic_link_up(__u8 port)
+{
+ unsigned int relax_time, max_time;
+ relax_time = 500;
+ max_time = 30000; /* 30 seconds */
+ int rc;
+ unsigned int i, error = 1;
+ __u16 status;
+ struct port_info_st pi_var;
+ __u8 port_state;
+
+ for (i = 0; i < max_time; i += relax_time) {
+ rc = get_port_info(port, &pi_var, &status);
+ if (rc) {
+ eprintf("");
+ return rc;
+ } else {
+ if (status == 0) {
+ port_state = (pi_var.combined4 >> 24) & 0xf;
+ //port_state= pi_var.port_state;
+ if (port_state == 4) {
+ error = 0;
+ break;
+ }
+ }
+ }
+ printf("+");
+ mdelay(relax_time);
+ }
+
+ if (i >= max_time)
+ return -1;
+
+ return 0;
+}
+
+static int ib_driver_init(struct pci_device *pci, udqp_t * ipoib_qph_p)
+{
+ int rc;
+ __u8 port;
+ __u16 status;
+ __u32 qkey;
+ __u16 mlid;
+ ud_av_t av;
+ struct ib_eqe_st ib_eqe;
+ __u8 num_eqe;
+
+ tprintf("");
+ rc = ib_device_init(pci);
+ if (rc)
+ return rc;
+
+ tprintf("");
+
+ memcpy(ib_data.bcast_gid.raw, ipv4_bcast_gid, sizeof(ipv4_bcast_gid));
+
+ port = PXE_IB_PORT;
+ rc = setup_hca(port, &ib_data.eq);
+ if (rc)
+ return rc;
+ tprintf("setup_hca() success");
+
+ ib_data.port = port;
+
+ if(print_info)
+ printf("boot port = %d\n", ib_data.port);
+
+ rc = wait_logic_link_up(port);
+ if (rc)
+ return rc;
+
+ tprintf("wait_logic_link_up() success");
+
+ rc = get_guid_info(&status);
+ if (rc) {
+ eprintf("");
+ return rc;
+ } else if (status) {
+ eprintf("");
+ return rc;
+ }
+
+ tprintf("get_guid_info() success");
+
+ /* this to flush stdout that contains previous chars */
+ printf(" \n");
+ if(print_info) {
+ __u8 *gid=ib_data.port_gid.raw;
+
+ printf("\n");
+ printf("port GID=%hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx:"
+ "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx\n",
+ gid[0],gid[1],gid[2],gid[3],gid[4],gid[5],gid[6],gid[7],
+ gid[8],gid[9],gid[10],gid[11],gid[12],gid[13],gid[14],gid[15]);
+ }
+
+ rc = get_pkey_tbl(NULL, &status);
+ if (rc) {
+ eprintf("");
+ return rc;
+ } else if (status) {
+ eprintf("");
+ return rc;
+ }
+ rc = create_mads_qp(&ib_data.mads_qp,
+ &ib_data.mads_snd_cq, &ib_data.mads_rcv_cq);
+ if (rc) {
+ eprintf("");
+ return rc;
+ }
+
+ tprintf("attempt to join mcast group ...");
+ rc = join_mc_group(&qkey, &mlid, 1);
+ if (rc) {
+ eprintf("");
+ return rc;
+ } else {
+ tprintf("join_mc_group() successfull qkey=0x%lx, mlid=0x%x",
+ qkey, mlid);
+ }
+
+ rc = create_ipoib_qp(&ib_data.ipoib_qp,
+ &ib_data.ipoib_snd_cq,
+ &ib_data.ipoib_rcv_cq, qkey);
+ if (rc) {
+ eprintf("");
+ return rc;
+ }
+
+ tprintf("create_ipoib_qp() success");
+ *ipoib_qph_p = ib_data.ipoib_qp;
+
+ tprintf("register qp to receive mcast...");
+ rc = add_qp_to_mcast_group(ib_data.bcast_gid, 1);
+ if (rc) {
+ eprintf("");
+ return rc;
+ } else {
+ tprintf("add_qp_to_mcast_group() success");
+ }
+
+ /* create a broadcast group ud AV */
+ av = alloc_ud_av();
+ if (!av) {
+ eprintf("");
+ return -1;
+ }
+ tprintf("alloc_ud_av() success");
+ modify_av_params(av, mlid, 1, 0, 0, &ib_data.bcast_gid, BCAST_QPN);
+ tprintf("modify_av_params() success");
+ ib_data.bcast_av = av;
+
+ do {
+ rc = poll_eq(&ib_eqe, &num_eqe);
+ if (rc) {
+ eprintf("");
+ return -1;
+ }
+ if (num_eqe) {
+ tprintf("num_eqe=%d", num_eqe);
+ }
+ tprintf("num_eqe=%d", num_eqe);
+ } while (num_eqe);
+ tprintf("eq is drained");
+
+ clear_interrupt();
+
+ return rc;
+}
+
+static int ib_driver_close(int fw_fatal)
+{
+ int rc, ret = 0;
+ __u32 qkey;
+ __u16 mlid;
+
+ rc = ib_device_close();
+ if (rc) {
+ eprintf("ib_device_close() failed");
+ ret = 1;
+ }
+
+ tprintf("");
+ if (!fw_fatal) {
+ rc = join_mc_group(&qkey, &mlid, 0);
+ if (rc) {
+ eprintf("");
+ ret = 1;
+ }
+ tprintf("join_mc_group(leave) success");
+
+ rc = add_qp_to_mcast_group(ib_data.bcast_gid, 0);
+ if (rc) {
+ eprintf("");
+ ret = 1;
+ }
+ tprintf("add_qp_to_mcast_group(remove) success");
+
+ rc = cmd_close_ib(ib_data.port);
+ if (rc) {
+ eprintf("");
+ ret = 1;
+ }
+ tprintf("cmd_close_ib(%d) success", ib_data.port);
+
+ if (destroy_udqp(ib_data.mads_qp)) {
+ eprintf("");
+ ret = 1;
+ }
+
+ if (destroy_udqp(ib_data.ipoib_qp)) {
+ eprintf("");
+ ret = 1;
+ }
+ }
+
+ rc = cmd_close_hca(fw_fatal);
+ if (rc) {
+ eprintf("");
+ ret = 1;
+ }
+
+ if (!fw_fatal) {
+ rc = cmd_sys_dis();
+ if (rc) {
+ eprintf("");
+ ret = 1;
+ }
+ }
+
+ return ret;
+}
+
+static int poll_cqe_tout(cq_t cqh, __u16 tout, void **wqe, int *good_p)
+{
+ int rc;
+ struct ib_cqe_st ib_cqe;
+ __u8 num_cqes;
+ unsigned long end;
+
+ end = currticks() + tout;
+ do {
+ rc = ib_poll_cq(cqh, &ib_cqe, &num_cqes);
+ if (rc)
+ return rc;
+
+ if (num_cqes == 1) {
+ if (good_p) {
+ *good_p = ib_cqe.is_error ? 0 : 1;
+ }
+ if (wqe)
+ *wqe = ib_cqe.wqe;
+ return 0;
+ }
+ }
+ while (currticks() < end);
+
+ return -1;
+}
+
+static u8 *get_port_gid(void)
+{
+ return ib_data.port_gid.raw;
+}
+
+static __u32 ib_get_qpn(udqp_t qph)
+{
+ __u32 qpn;
+
+ qpn = dev_get_qpn(qph);
+
+ return qpn;
+}
+
+static int drain_eq(void)
+{
+ __u8 num_eqe = 0, tot_eqe = 0;
+ int rc;
+
+ do {
+ tot_eqe += num_eqe;
+ rc = poll_eq(ib_data.eq, &num_eqe);
+ if (rc) {
+ eprintf("");
+ return -1;
+ }
+
+ tprintf("num_eqe=%d", num_eqe);
+ } while (num_eqe);
+ tprintf("eq is drained");
+ if (tot_eqe) {
+ tprintf("got %d eqes", tot_eqe);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int poll_error_buf(void)
+{
+ __u32 *ptr= dev_ib_data.error_buf_addr;
+ __u32 i;
+
+ for (i=0; i<dev_ib_data.error_buf_size; ++i, ptr++) {
+ if ( readl(ptr) ) {
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+
diff --git a/src/drivers/net/mlx_ipoib/ib_driver.h b/src/drivers/net/mlx_ipoib/ib_driver.h
new file mode 100644
index 000000000..305bb5d4d
--- /dev/null
+++ b/src/drivers/net/mlx_ipoib/ib_driver.h
@@ -0,0 +1,169 @@
+/*
+ This software is available to you under a choice of one of two
+ licenses. You may choose to be licensed under the terms of the GNU
+ General Public License (GPL) Version 2, available at
+ <http://www.fsf.org/copyleft/gpl.html>, or the OpenIB.org BSD
+ license, available in the LICENSE.TXT file accompanying this
+ software. These details are also available at
+ <http://openib.org/license.html>.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+
+ Copyright (c) 2004 Mellanox Technologies Ltd. All rights reserved.
+*/
+
+#ifndef __ib_driver_h__
+#define __ib_driver_h__
+
+#define MELLANOX_VENDOR_ID 0x15b3
+
+#define GLOBAL_PD 0x123456
+#define GLOBAL_QKEY 0x80010000
+
+#define MAD_BUF_SZ 256
+#define IPOIB_RCV_BUF_SZ 2048
+#define IPOIB_SND_BUF_SZ 2048
+#define GRH_SIZE 40
+
+#define ARP_BUF_SZ 56
+
+#define FL_EOL 255 /* end of free list */
+
+#define SEND_CQE_POLL_TOUT 38 /* 2 sec */
+#define SA_RESP_POLL_TOUT 91 /* 5 seconds */
+
+#define NUM_AVS 10
+
+#define PXE_IB_PORT 1
+
+#define SA_QPN 1
+#define BCAST_QPN 0xffffff
+
+#define QPN_BASE 0x550000
+
+enum {
+ MADS_QPN_SN,
+ IPOIB_QPN_SN,
+ MAX_APP_QPS
+};
+
+enum {
+ MADS_SND_CQN_SN,
+ MADS_RCV_CQN_SN,
+ IPOIB_SND_CQN_SN,
+ IPOIB_RCV_CQN_SN,
+ MAX_APP_CQS
+};
+
+enum {
+ MTU_256 = 1,
+ MTU_512 = 2,
+ MTU_1024 = 3,
+ MTU_2048 = 4,
+};
+
+#define HCR_BASE 0x80680
+#define HCR_OFFSET_GO 0x80698
+#define HCR_OFFSET_STATUS 0x80698
+#define HCR_OFFSET_OUTPRM_H 0x8068C
+#define HCR_OFFSET_OUTPRM_L 0x80690
+
+#define MKEY_PREFIX 0x77000000
+#define MKEY_IDX_MASK 0xffffff
+
+/* event types */
+/*=============*/
+/* Completion Events */
+#define XDEV_EV_TYPE_CQ_COMP 0
+
+ /* IB - affiliated errors CQ */
+#define XDEV_EV_TYPE_CQ_ERR 0x04
+#define XDEV_EV_TYPE_LOCAL_WQ_CATAS_ERR 0x05
+
+ /* Unaffiliated errors */
+#define XDEV_EV_TYPE_PORT_ERR 0x09
+#define XDEV_EV_TYPE_LOCAL_WQ_INVALID_REQ_ERR 0x10
+#define XDEV_EV_TYPE_LOCAL_WQ_ACCESS_VIOL_ERR 0x11
+
+/* NOPCODE field enumeration for doorbells and send-WQEs */
+#define XDEV_NOPCODE_SEND 10 /* Send */
+
+struct ib_gid_u32_st {
+ __u32 dw[4];
+};
+
+union ib_gid_u {
+ __u8 raw[16];
+ struct ib_gid_u32_st as_u32;
+} __attribute__ ((packed));
+
+struct ib_cqe_st {
+ __u8 is_error;
+ __u8 is_send;
+ void *wqe;
+ __u32 count;
+};
+
+typedef void *udqp_t;
+typedef void *cq_t;
+typedef void *ud_av_t;
+typedef void *ud_send_wqe_t;
+typedef void *eq_t;
+
+struct ib_data_st {
+// __u32 mkey;
+// __u32 pd;
+// __u32 qkey;
+ udqp_t mads_qp;
+ udqp_t ipoib_qp;
+ cq_t mads_snd_cq;
+ cq_t mads_rcv_cq;
+ cq_t ipoib_snd_cq;
+ cq_t ipoib_rcv_cq;
+ eq_t eq;
+ __u16 sm_lid;
+ __u16 pkey;
+ union ib_gid_u port_gid;
+ union ib_gid_u bcast_gid;
+ ud_av_t bcast_av; /* av allocated and used solely for broadcast */
+ __u8 port;
+};
+
+static int setup_hca(__u8 port, void **eq_p);
+static int post_send_req(udqp_t qp, ud_send_wqe_t wqe, __u8 num_gather);
+static void prep_send_wqe_buf(udqp_t qp,
+ ud_av_t av,
+ ud_send_wqe_t wqe,
+ const void *buf,
+ unsigned int offset, __u16 len, __u8 e);
+
+static int create_mads_qp(void **qp_pp, void **snd_cq_pp, void **rcv_cq_pp);
+
+static int create_ipoib_qp(udqp_t * qp_p,
+ void **snd_cq_pp, void **rcv_cq_pp, __u32 qkey);
+
+static int gw_read_cr(__u32 addr, __u32 * result);
+static int gw_write_cr(__u32 addr, __u32 data);
+static ud_av_t alloc_ud_av(void);
+static void free_ud_av(ud_av_t av);
+static int ib_poll_cq(cq_t cq, struct ib_cqe_st *ib_cqe_p, __u8 * num_cqes);
+static int add_qp_to_mcast_group(union ib_gid_u mcast_gid, __u8 add);
+static int clear_interrupt(void);
+static int poll_cqe_tout(cq_t cqh, __u16 tout, void **wqe, int *good_p);
+
+static void *get_inprm_buf(void);
+static void *get_outprm_buf(void);
+static __u32 ib_get_qpn(udqp_t qph);
+
+static void dev_post_dbell(void *dbell, __u32 offset);
+
+static struct ib_data_st ib_data;
+
+#endif /* __ib_driver_h__ */
diff --git a/src/drivers/net/mlx_ipoib/ib_mad.c b/src/drivers/net/mlx_ipoib/ib_mad.c
new file mode 100644
index 000000000..3e263a5b4
--- /dev/null
+++ b/src/drivers/net/mlx_ipoib/ib_mad.c
@@ -0,0 +1,396 @@
+/*
+ This software is available to you under a choice of one of two
+ licenses. You may choose to be licensed under the terms of the GNU
+ General Public License (GPL) Version 2, available at
+ <http://www.fsf.org/copyleft/gpl.html>, or the OpenIB.org BSD
+ license, available in the LICENSE.TXT file accompanying this
+ software. These details are also available at
+ <http://openib.org/license.html>.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+
+ Copyright (c) 2004 Mellanox Technologies Ltd. All rights reserved.
+*/
+
+#include "ib_mad.h"
+#include "mad_attrib.h"
+#include "cmdif.h"
+#include "ib_driver.h"
+
+#define TID_START 0x1234
+#define TID_INC 117
+
+static u32 next_tid = TID_START;
+
+/*
+ * get_port_info
+ *
+ * query the local device for the portinfo attribute
+ *
+ * port(in) port number to query
+ * buf(out) buffer to hold the result
+ */
+static int get_port_info(__u8 port, struct port_info_st *buf, __u16 * status)
+{
+ union port_info_mad_u *inprm;
+ union port_info_mad_u *outprm;
+ int rc;
+
+ inprm = get_inprm_buf();
+ outprm = get_outprm_buf();
+ memset(inprm, 0, sizeof *inprm);
+
+ inprm->mad.mad_hdr.method = IB_MGMT_METHOD_GET;
+ inprm->mad.mad_hdr.mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED;
+ inprm->mad.mad_hdr.class_version = 1;
+ inprm->mad.mad_hdr.base_version = IB_MGMT_BASE_VERSION;
+ inprm->mad.mad_hdr.attr_id = IB_SMP_ATTR_PORT_INFO;
+ inprm->mad.mad_hdr.attr_mod = port;
+
+ rc = cmd_mad_ifc(inprm, (struct ib_mad_st *)outprm, port);
+ if (!rc) {
+ memcpy(buf, &outprm->mad.port_info,
+ sizeof(outprm->mad.port_info));
+ *status = inprm->mad.mad_hdr.status;
+ if (!(*status)) {
+ ib_data.sm_lid = outprm->mad.port_info.mastersm_lid;
+ memcpy(&ib_data.port_gid.raw[0],
+ outprm->mad.port_info.gid_prefix, 8);
+ cpu_to_be_buf(&ib_data.port_gid.raw[0], 8);
+ }
+ }
+ return rc;
+}
+
+/*
+ * get_guid_info
+ *
+ * query the local device for the guidinfo attribute
+ *
+ * buf(out) buffer to hold the result
+ */
+static int get_guid_info(__u16 * status)
+{
+ union guid_info_mad_u *inprm;
+ union guid_info_mad_u *outprm;
+ int rc;
+
+ inprm = get_inprm_buf();
+ outprm = get_outprm_buf();
+ memset(inprm, 0, sizeof *inprm);
+
+ inprm->mad.mad_hdr.method = IB_MGMT_METHOD_GET;
+ inprm->mad.mad_hdr.mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED;
+ inprm->mad.mad_hdr.class_version = 1;
+ inprm->mad.mad_hdr.base_version = IB_MGMT_BASE_VERSION;
+ inprm->mad.mad_hdr.attr_id = IB_SMP_ATTR_GUID_INFO;
+ inprm->mad.mad_hdr.attr_mod = 0;
+
+ rc = cmd_mad_ifc(inprm, (struct ib_mad_st *)outprm, ib_data.port);
+ if (!rc) {
+ *status = inprm->mad.mad_hdr.status;
+ if (!(*status)) {
+ memcpy(&ib_data.port_gid.raw[8],
+ &outprm->mad.guid_info.gid_tbl[0], 8);
+ cpu_to_be_buf(&ib_data.port_gid.raw[8], 8);
+ }
+ }
+ return rc;
+}
+
+static int get_pkey_tbl(struct pkey_tbl_st *pkey_tbl, __u16 * status)
+{
+ union pkey_tbl_mad_u *inprm;
+ union pkey_tbl_mad_u *outprm;
+ int rc;
+
+ inprm = get_inprm_buf();
+ outprm = get_outprm_buf();
+ memset(inprm, 0, sizeof *inprm);
+ memset(outprm, 0, sizeof *outprm);
+
+ inprm->mad.mad_hdr.method = IB_MGMT_METHOD_GET;
+ inprm->mad.mad_hdr.mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED;
+ inprm->mad.mad_hdr.class_version = 1;
+ inprm->mad.mad_hdr.base_version = IB_MGMT_BASE_VERSION;
+ inprm->mad.mad_hdr.attr_id = IB_SMP_ATTR_PKEY_TABLE;
+ inprm->mad.mad_hdr.attr_mod = 0;
+
+ rc = cmd_mad_ifc(inprm, (struct ib_mad_st *)outprm, 1);
+ if (!rc) {
+ if (pkey_tbl)
+ memcpy(pkey_tbl, &outprm->mad.pkey_tbl, 2);
+ *status = inprm->mad.mad_hdr.status;
+ if (!(*status)) {
+ ib_data.pkey = outprm->mad.pkey_tbl.pkey_tbl[0][1];
+ ib_data.bcast_gid.raw[4] =
+ outprm->mad.pkey_tbl.pkey_tbl[0][1] >> 8;
+ ib_data.bcast_gid.raw[5] =
+ outprm->mad.pkey_tbl.pkey_tbl[0][1] & 0xff;
+ }
+ }
+ return rc;
+}
+
+static int join_mc_group(__u32 * qkey_p, __u16 * mlid_p, __u8 join)
+{
+ struct mc_member_mad_st *mad, *rcv_mad;
+ void *snd_wqe;
+ void *tmp_wqe;
+ udqp_t qp;
+ void *av;
+ int rc;
+ u32 tid;
+ void *rcv_wqe;
+ int is_good;
+
+ qp = ib_data.mads_qp;
+
+ snd_wqe = alloc_send_wqe(qp);
+ if (!snd_wqe) {
+ eprintf("");
+ return -1;
+ }
+ tprintf("allocated snd_wqe=0x%lx", snd_wqe);
+
+ mad = get_send_wqe_buf(snd_wqe, 0);
+ memset(mad, 0, 256);
+
+ av = alloc_ud_av();
+ if (!av) {
+ eprintf("");
+ free_wqe(snd_wqe);
+ return -1;
+ }
+ modify_av_params(av, ib_data.sm_lid, 0, 0, 0, NULL, SA_QPN);
+
+ prep_send_wqe_buf(qp, av, snd_wqe, NULL, 0, 256, 0);
+
+ mad->mad_hdr.method = join ? IB_MGMT_METHOD_SET : IB_MGMT_METHOD_DELETE;
+ mad->mad_hdr.mgmt_class = IB_MGMT_CLASS_SUBN_ADM;
+ mad->mad_hdr.class_version = 2;
+ mad->mad_hdr.base_version = IB_MGMT_BASE_VERSION;
+ mad->mad_hdr.attr_id = IB_SA_ATTR_MC_MEMBER_REC;
+ tid = next_tid;
+ next_tid += TID_INC;
+ mad->mad_hdr.tid[1] = tid;
+
+ mad->sa_hdr.comp_mask[1] = IB_SA_MCMEMBER_REC_MGID |
+ IB_SA_MCMEMBER_REC_PORT_GID | IB_SA_MCMEMBER_REC_JOIN_STATE;
+
+ mad->mc_member.combined4 |= (1 << 24); /*mad->mc_member.join_state = 1; */
+
+ be_to_cpu_buf(mad, sizeof *mad);
+ memcpy(mad->mc_member.mgid, ib_data.bcast_gid.raw, 16);
+ memcpy(mad->mc_member.port_gid, ib_data.port_gid.raw, 16);
+
+ rc = post_send_req(qp, snd_wqe, 1);
+ if (rc) {
+ eprintf("");
+ free_ud_av(av);
+ free_wqe(snd_wqe);
+ return -1;
+ }
+
+ tprintf("");
+ /* poll the CQ to get the completions
+ on the send and the expected receive */
+
+ /* send completion */
+ rc = poll_cqe_tout(ib_data.mads_snd_cq, SEND_CQE_POLL_TOUT, &tmp_wqe,
+ &is_good);
+ if (rc) {
+ eprintf("");
+ return -1;
+ }
+
+ if (tmp_wqe != snd_wqe) {
+ eprintf("");
+ return -1;
+ }
+
+ if (free_wqe(snd_wqe)) {
+ eprintf("");
+ return -1;
+ }
+ free_ud_av(av);
+
+ if (!is_good) {
+ eprintf("");
+ return -1;
+ }
+
+ /* receive completion */
+ rc = poll_cqe_tout(ib_data.mads_rcv_cq, SA_RESP_POLL_TOUT, &rcv_wqe,
+ &is_good);
+ if (rc) {
+ eprintf("");
+ return -1;
+ }
+
+ if (is_good) {
+ rcv_mad = get_rcv_wqe_buf(rcv_wqe, 1);
+ be_to_cpu_buf(rcv_mad, sizeof *rcv_mad);
+ if (rcv_mad->mad_hdr.tid[1] == tid) {
+ /* that's our response */
+ if (mad->mad_hdr.status == 0) {
+ /* good response - save results */
+ *qkey_p = rcv_mad->mc_member.q_key;
+ *mlid_p = rcv_mad->mc_member.combined1 >> 16; // rcv_mad->mc_member.mlid;
+ } else {
+ /* join failed */
+ eprintf("");
+ return -1;
+ }
+ } else {
+ /* not our response */
+ eprintf("");
+ return -1;
+ }
+ }
+
+ if (free_wqe(rcv_wqe)) {
+ eprintf("");
+ return -1;
+ }
+
+ return is_good ? 0 : -1;
+}
+
+static int get_path_record(union ib_gid_u *dgid, __u16 * dlid_p, u8 * sl_p,
+ u8 * rate_p)
+{
+ struct path_record_mad_st *mad, *rcv_mad;
+ void *snd_wqe;
+ udqp_t qp;
+ ud_av_t av;
+ void *tmp_wqe;
+ void *rcv_wqe;
+ u32 tid;
+ int rc;
+ int is_good;
+
+ tprintf("gid=%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:"
+ "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
+ dgid->raw[0], dgid->raw[1], dgid->raw[2], dgid->raw[3],
+ dgid->raw[4], dgid->raw[5], dgid->raw[6], dgid->raw[7],
+ dgid->raw[8], dgid->raw[9], dgid->raw[10], dgid->raw[11],
+ dgid->raw[12], dgid->raw[13], dgid->raw[14], dgid->raw[15]);
+ qp = ib_data.mads_qp;
+
+ snd_wqe = alloc_send_wqe(qp);
+ if (!snd_wqe) {
+ eprintf("");
+ return -1;
+ }
+
+ mad = get_send_wqe_buf(snd_wqe, 0);
+ memset(mad, 0, 256);
+
+ av = alloc_ud_av();
+ if (!av) {
+ eprintf("");
+ free_wqe(snd_wqe);
+ return -1;
+ }
+ modify_av_params(av, ib_data.sm_lid, 0, 0, 0, NULL, SA_QPN);
+
+ prep_send_wqe_buf(qp, av, snd_wqe, NULL, 0, 256, 0);
+
+ mad->mad_hdr.method = IB_MGMT_METHOD_GET;
+ mad->mad_hdr.mgmt_class = IB_MGMT_CLASS_SUBN_ADM;
+ mad->mad_hdr.class_version = 2;
+ mad->mad_hdr.base_version = IB_MGMT_BASE_VERSION;
+ mad->mad_hdr.attr_id = IB_SA_ATTR_PATH_REC;
+ tid = next_tid;
+ next_tid += TID_INC;
+ mad->mad_hdr.tid[1] = tid;
+
+ memcpy(mad->path_record.dgid.raw, dgid->raw, 16);
+ cpu_to_be_buf(mad->path_record.dgid.raw, 16);
+
+ mad->sa_hdr.comp_mask[1] = IB_SA_PATH_REC_DGID | IB_SA_PATH_REC_SGID;
+
+ cpu_to_be_buf(mad, sizeof *mad);
+ memcpy(mad->path_record.sgid.raw, ib_data.port_gid.raw, 16);
+
+ rc = post_send_req(qp, snd_wqe, 1);
+ if (rc) {
+ eprintf("");
+ free_ud_av(av);
+ free_wqe(snd_wqe);
+ return rc;
+ }
+
+ /* poll the CQ to get the completions
+ on the send and the expected receive */
+
+ /* send completion */
+ rc = poll_cqe_tout(ib_data.mads_snd_cq, SEND_CQE_POLL_TOUT, &tmp_wqe,
+ &is_good);
+ if (rc) {
+ eprintf("");
+ return -1;
+ }
+
+ if (tmp_wqe != snd_wqe) {
+ eprintf("");
+ return -1;
+ }
+
+ if (free_wqe(snd_wqe)) {
+ eprintf("");
+ return -1;
+ }
+ free_ud_av(av);
+
+ if (!is_good) {
+ eprintf("");
+ return -1;
+ }
+
+ /* receive completion */
+ rc = poll_cqe_tout(ib_data.mads_rcv_cq, SA_RESP_POLL_TOUT, &rcv_wqe,
+ &is_good);
+ if (rc) {
+ eprintf("");
+ return -1;
+ }
+
+ if (is_good) {
+ rcv_mad = get_rcv_wqe_buf(rcv_wqe, 1);
+ be_to_cpu_buf(rcv_mad, sizeof *rcv_mad);
+ if (rcv_mad->mad_hdr.tid[1] == tid) {
+ /* that's our response */
+ if (mad->mad_hdr.status == 0) {
+ /* good response - save results */
+ *dlid_p = rcv_mad->path_record.dlid;
+ *sl_p = (rcv_mad->path_record.combined3 >> 16) & 0xf; // rcv_mad->path_record.sl;
+ *rate_p = rcv_mad->path_record.combined3 & 0x3f; //rcv_mad->path_record.rate;
+ } else {
+ /* join failed */
+ eprintf("");
+ return -1;
+ }
+ } else {
+ /* not our response */
+ eprintf("");
+ return -1;
+ }
+ }
+
+ if (free_wqe(rcv_wqe)) {
+ eprintf("");
+ return -1;
+ }
+
+ tprintf("");
+ return is_good ? 0 : -1;
+}
diff --git a/src/drivers/net/mlx_ipoib/ib_mad.h b/src/drivers/net/mlx_ipoib/ib_mad.h
new file mode 100644
index 000000000..5ffb54045
--- /dev/null
+++ b/src/drivers/net/mlx_ipoib/ib_mad.h
@@ -0,0 +1,110 @@
+/*
+ This software is available to you under a choice of one of two
+ licenses. You may choose to be licensed under the terms of the GNU
+ General Public License (GPL) Version 2, available at
+ <http://www.fsf.org/copyleft/gpl.html>, or the OpenIB.org BSD
+ license, available in the LICENSE.TXT file accompanying this
+ software. These details are also available at
+ <http://openib.org/license.html>.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+
+ Copyright (c) 2004 Mellanox Technologies Ltd. All rights reserved.
+*/
+
+#ifndef __ib_mad_h__
+#define __ib_mad_h__
+
+#include "ib_driver.h"
+
+/* Management base version */
+#define IB_MGMT_BASE_VERSION 1
+
+/* Management classes */
+#define IB_MGMT_CLASS_SUBN_LID_ROUTED 0x01
+#define IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE 0x81
+#define IB_MGMT_CLASS_SUBN_ADM 0x03
+#define IB_MGMT_CLASS_PERF_MGMT 0x04
+#define IB_MGMT_CLASS_BM 0x05
+#define IB_MGMT_CLASS_DEVICE_MGMT 0x06
+#define IB_MGMT_CLASS_CM 0x07
+#define IB_MGMT_CLASS_SNMP 0x08
+#define IB_MGMT_CLASS_VENDOR_RANGE2_START 0x30
+#define IB_MGMT_CLASS_VENDOR_RANGE2_END 0x4F
+
+/* Management methods */
+#define IB_MGMT_METHOD_GET 0x01
+#define IB_MGMT_METHOD_SET 0x02
+#define IB_MGMT_METHOD_GET_RESP 0x81
+#define IB_MGMT_METHOD_SEND 0x03
+#define IB_MGMT_METHOD_TRAP 0x05
+#define IB_MGMT_METHOD_REPORT 0x06
+#define IB_MGMT_METHOD_REPORT_RESP 0x86
+#define IB_MGMT_METHOD_TRAP_REPRESS 0x07
+#define IB_MGMT_METHOD_DELETE 0x15
+
+#define IB_MGMT_METHOD_RESP 0x80
+
+/* Subnet management attributes */
+#define IB_SMP_ATTR_NOTICE 0x0002
+#define IB_SMP_ATTR_NODE_DESC 0x0010
+#define IB_SMP_ATTR_NODE_INFO 0x0011
+#define IB_SMP_ATTR_SWITCH_INFO 0x0012
+#define IB_SMP_ATTR_GUID_INFO 0x0014
+#define IB_SMP_ATTR_PORT_INFO 0x0015
+#define IB_SMP_ATTR_PKEY_TABLE 0x0016
+#define IB_SMP_ATTR_SL_TO_VL_TABLE 0x0017
+#define IB_SMP_ATTR_VL_ARB_TABLE 0x0018
+#define IB_SMP_ATTR_LINEAR_FORWARD_TABLE 0x0019
+#define IB_SMP_ATTR_RANDOM_FORWARD_TABLE 0x001A
+#define IB_SMP_ATTR_MCAST_FORWARD_TABLE 0x001B
+#define IB_SMP_ATTR_SM_INFO 0x0020
+#define IB_SMP_ATTR_VENDOR_DIAG 0x0030
+#define IB_SMP_ATTR_LED_INFO 0x0031
+#define IB_SMP_ATTR_VENDOR_MASK 0xFF00
+
+struct ib_mad_hdr_st {
+ __u8 method;
+ __u8 class_version;
+ __u8 mgmt_class;
+ __u8 base_version;
+ __u16 class_specific;
+ __u16 status;
+ __u32 tid[2];
+ __u16 resv;
+ __u16 attr_id;
+ __u32 attr_mod;
+} __attribute__ ((packed));
+
+struct rmpp_hdr_st {
+ __u32 raw[3];
+} __attribute__ ((packed));
+
+struct sa_header_st {
+ __u32 sm_key[2];
+ __u16 attrib_offset;
+ __u16 r0;
+ __u32 comp_mask[2];
+} __attribute__ ((packed));
+
+struct ib_mad_st {
+ struct ib_mad_hdr_st mad_hdr;
+ __u8 data[232];
+} __attribute__ ((packed));
+
+union mad_u {
+ __u8 raw[256];
+ struct ib_mad_st mad;
+} __attribute__ ((packed));
+
+static int get_path_record(union ib_gid_u *dgid, __u16 * dlid_p, __u8 * sl_p,
+ __u8 * rate_p);
+
+#endif /* __ib_mad_h__ */
diff --git a/src/drivers/net/mlx_ipoib/ib_mt23108.c b/src/drivers/net/mlx_ipoib/ib_mt23108.c
new file mode 100644
index 000000000..0291f46c0
--- /dev/null
+++ b/src/drivers/net/mlx_ipoib/ib_mt23108.c
@@ -0,0 +1,1701 @@
+/*
+ This software is available to you under a choice of one of two
+ licenses. You may choose to be licensed under the terms of the GNU
+ General Public License (GPL) Version 2, available at
+ <http://www.fsf.org/copyleft/gpl.html>, or the OpenIB.org BSD
+ license, available in the LICENSE.TXT file accompanying this
+ software. These details are also available at
+ <http://openib.org/license.html>.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+
+ Copyright (c) 2004 Mellanox Technologies Ltd. All rights reserved.
+*/
+
+#include "mt23108.h"
+#include "ib_driver.h"
+#include "pci.h"
+
+struct device_buffers_st {
+ union recv_wqe_u mads_qp_rcv_queue[NUM_MADS_RCV_WQES]
+ __attribute__ ((aligned(RECV_WQE_U_ALIGN)));
+ union recv_wqe_u ipoib_qp_rcv_queue[NUM_IPOIB_RCV_WQES]
+ __attribute__ ((aligned(RECV_WQE_U_ALIGN)));
+ union ud_send_wqe_u mads_qp_snd_queue[NUM_MADS_SND_WQES]
+ __attribute__ ((aligned(UD_SEND_WQE_U_ALIGN)));
+ union ud_send_wqe_u ipoib_qp_snd_queue[NUM_IPOIB_SND_WQES]
+ __attribute__ ((aligned(UD_SEND_WQE_U_ALIGN)));
+ u8 inprm_buf[INPRM_BUF_SZ] __attribute__ ((aligned(INPRM_BUF_ALIGN)));
+ u8 outprm_buf[OUTPRM_BUF_SZ]
+ __attribute__ ((aligned(OUTPRM_BUF_ALIGN)));
+ struct eqe_t eq_buf[1 << LOG2_EQ_SZ]
+ __attribute__ ((aligned(sizeof(struct eqe_t))));
+ union cqe_st mads_snd_cq_buf[NUM_MADS_SND_CQES]
+ __attribute__ ((aligned(sizeof(union cqe_st))));
+ union cqe_st ipoib_snd_cq_buf[NUM_IPOIB_SND_CQES]
+ __attribute__ ((aligned(sizeof(union cqe_st))));
+ union cqe_st mads_rcv_cq_buf[NUM_MADS_RCV_CQES]
+ __attribute__ ((aligned(sizeof(union cqe_st))));
+ union cqe_st ipoib_rcv_cq_buf[NUM_IPOIB_RCV_CQES]
+ __attribute__ ((aligned(sizeof(union cqe_st))));
+ union ud_av_u av_array[NUM_AVS]
+ __attribute__ ((aligned(ADDRESS_VECTOR_ST_ALIGN)));
+} __attribute__ ((packed));
+
+#define STRUCT_ALIGN_SZ 4096
+#define SRC_BUF_SZ (sizeof(struct device_buffers_st) + STRUCT_ALIGN_SZ - 1)
+
+/* the following must be kept in this order
+ for the memory region to cover the buffers */
+static u8 src_buf[SRC_BUF_SZ];
+static struct ib_buffers_st ib_buffers;
+static __u32 memreg_size;
+/* end of order constraint */
+
+static struct dev_pci_struct tavor_pci_dev;
+static struct device_buffers_st *dev_buffers_p;
+static struct device_ib_data_st dev_ib_data;
+
+static int gw_write_cr(__u32 addr, __u32 data)
+{
+ writel(htonl(data), tavor_pci_dev.cr_space + addr);
+ return 0;
+}
+
+static int gw_read_cr(__u32 addr, __u32 * result)
+{
+ *result = ntohl(readl(tavor_pci_dev.cr_space + addr));
+ return 0;
+}
+
+static int reset_hca(void)
+{
+ return gw_write_cr(TAVOR_RESET_OFFSET, 1);
+}
+
+static int find_mlx_bridge(__u8 hca_bus, __u8 * br_bus_p, __u8 * br_devfn_p)
+{
+ int bus;
+ int dev;
+ int devfn;
+ int rc;
+ __u16 vendor, dev_id;
+ __u8 sec_bus;
+
+ for (bus = 0; bus < 256; ++bus) {
+ for (dev = 0; dev < 32; ++dev) {
+ devfn = (dev << 3);
+ rc = pcibios_read_config_word(bus, devfn, PCI_VENDOR_ID,
+ &vendor);
+ if (rc)
+ return rc;
+
+ if (vendor != MELLANOX_VENDOR_ID)
+ continue;
+
+ rc = pcibios_read_config_word(bus, devfn, PCI_DEVICE_ID,
+ &dev_id);
+ if (rc)
+ return rc;
+
+ if (dev_id != TAVOR_BRIDGE_DEVICE_ID)
+ continue;
+
+ rc = pcibios_read_config_byte(bus, devfn,
+ PCI_SECONDARY_BUS,
+ &sec_bus);
+ if (rc)
+ return rc;
+
+ if (sec_bus == hca_bus) {
+ *br_bus_p = bus;
+ *br_devfn_p = devfn;
+ return 0;
+ }
+ }
+ }
+
+ return -1;
+}
+
+static int ib_device_init(struct pci_device *dev)
+{
+ int i;
+ int rc;
+ __u8 br_bus, br_devfn;
+
+ tprintf("");
+
+ memset(&dev_ib_data, 0, sizeof dev_ib_data);
+
+ /* save bars */
+ tprintf("bus=%d devfn=0x%x", dev->bus, dev->devfn);
+ for (i = 0; i < 6; ++i) {
+ tavor_pci_dev.dev.bar[i] =
+ pci_bar_start(dev, PCI_BASE_ADDRESS_0 + (i << 2));
+ tprintf("bar[%d]= 0x%08lx", i, tavor_pci_dev.dev.bar[i]);
+ }
+
+ tprintf("");
+ /* save config space */
+ for (i = 0; i < 64; ++i) {
+ rc = pci_read_config_dword(dev, i << 2,
+ &tavor_pci_dev.dev.
+ dev_config_space[i]);
+ if (rc) {
+ eprintf("");
+ return rc;
+ }
+ tprintf("config[%d]= 0x%08lx", i << 2,
+ tavor_pci_dev.dev.dev_config_space[i]);
+ }
+
+ tprintf("");
+ tavor_pci_dev.dev.dev = dev;
+
+ tprintf("");
+ if (dev->dev_id == TAVOR_DEVICE_ID) {
+
+ rc = find_mlx_bridge(dev->bus, &br_bus, &br_devfn);
+ if (rc) {
+ eprintf("");
+ return rc;
+ }
+
+ tavor_pci_dev.br.bus = br_bus;
+ tavor_pci_dev.br.devfn = br_devfn;
+
+ tprintf("bus=%d devfn=0x%x", br_bus, br_devfn);
+ /* save config space */
+ for (i = 0; i < 64; ++i) {
+ rc = pcibios_read_config_dword(br_bus, br_devfn, i << 2,
+ &tavor_pci_dev.br.
+ dev_config_space[i]);
+ if (rc) {
+ eprintf("");
+ return rc;
+ }
+ tprintf("config[%d]= 0x%08lx", i << 2,
+ tavor_pci_dev.br.dev_config_space[i]);
+ }
+ }
+
+ tprintf("");
+
+ /* map cr-space */
+ tavor_pci_dev.cr_space = ioremap(tavor_pci_dev.dev.bar[0], 0x100000);
+ if (!tavor_pci_dev.cr_space) {
+ eprintf("");
+ return -1;
+ }
+
+ /* map uar */
+ tavor_pci_dev.uar =
+ ioremap(tavor_pci_dev.dev.bar[2] + UAR_IDX * 0x1000, 0x1000);
+ if (!tavor_pci_dev.uar) {
+ eprintf("");
+ return -1;
+ }
+ tprintf("uar_base (pa:va) = 0x%lx 0x%lx",
+ tavor_pci_dev.dev.bar[2] + UAR_IDX * 0x1000, tavor_pci_dev.uar);
+
+ tprintf("");
+
+ return 0;
+}
+
+static inline unsigned long lalign(unsigned long buf, unsigned long align)
+{
+ return (unsigned long)((buf + align - 1) &
+ (~(((unsigned long)align) - 1)));
+}
+
+static int init_dev_data(void)
+{
+ unsigned long tmp;
+
+ tmp = lalign(virt_to_bus(src_buf), STRUCT_ALIGN_SZ);
+
+ dev_buffers_p = bus_to_virt(tmp);
+ memreg_size = (__u32) (&memreg_size) - (__u32) dev_buffers_p;
+ tprintf("src_buf=0x%lx, dev_buffers_p=0x%lx, memreg_size=0x%x", src_buf,
+ dev_buffers_p, memreg_size);
+
+ return 0;
+}
+
+static int restore_config(void)
+{
+ int i;
+ int rc;
+
+ if (tavor_pci_dev.dev.dev->dev_id == TAVOR_DEVICE_ID) {
+ for (i = 0; i < 64; ++i) {
+ rc = pcibios_write_config_dword(tavor_pci_dev.br.bus,
+ tavor_pci_dev.br.devfn,
+ i << 2,
+ tavor_pci_dev.br.
+ dev_config_space[i]);
+ if (rc) {
+ return rc;
+ }
+ }
+ }
+
+ for (i = 0; i < 64; ++i) {
+ if (i != 22 && i != 23) {
+ rc = pci_write_config_dword(tavor_pci_dev.dev.dev,
+ i << 2,
+ tavor_pci_dev.dev.
+ dev_config_space[i]);
+ if (rc) {
+ return rc;
+ }
+ }
+ }
+ return 0;
+}
+
+static void prep_init_hca_buf(const struct init_hca_st *init_hca_p, void *buf)
+{
+ /*struct init_hca_param_st */ void *p = buf;
+ void *tmp;
+
+ memset(buf, 0, MT_STRUCT_SIZE(tavorprm_init_hca_st));
+
+ tmp =
+ p + MT_BYTE_OFFSET(tavorprm_init_hca_st,
+ qpc_eec_cqc_eqc_rdb_parameters);
+
+ INS_FLD(init_hca_p->qpc_base_addr_h, tmp, tavorprm_qpcbaseaddr_st,
+ qpc_base_addr_h);
+ INS_FLD(init_hca_p->
+ qpc_base_addr_l >> (32 -
+ (MT_BIT_SIZE
+ (tavorprm_qpcbaseaddr_st,
+ qpc_base_addr_l))), tmp,
+ tavorprm_qpcbaseaddr_st, qpc_base_addr_l);
+ INS_FLD(init_hca_p->log_num_of_qp, tmp, tavorprm_qpcbaseaddr_st,
+ log_num_of_qp);
+
+ INS_FLD(init_hca_p->cqc_base_addr_h, tmp, tavorprm_qpcbaseaddr_st,
+ cqc_base_addr_h);
+ INS_FLD(init_hca_p->
+ cqc_base_addr_l >> (32 -
+ (MT_BIT_SIZE
+ (tavorprm_qpcbaseaddr_st,
+ cqc_base_addr_l))), tmp,
+ tavorprm_qpcbaseaddr_st, cqc_base_addr_l);
+ INS_FLD(init_hca_p->log_num_of_cq, tmp, tavorprm_qpcbaseaddr_st,
+ log_num_of_cq);
+
+ INS_FLD(init_hca_p->eqc_base_addr_h, tmp, tavorprm_qpcbaseaddr_st,
+ eqc_base_addr_h);
+ INS_FLD(init_hca_p->
+ eqc_base_addr_l >> (32 -
+ (MT_BIT_SIZE
+ (tavorprm_qpcbaseaddr_st,
+ eqc_base_addr_l))), tmp,
+ tavorprm_qpcbaseaddr_st, eqc_base_addr_l);
+ INS_FLD(LOG2_EQS, tmp, tavorprm_qpcbaseaddr_st, log_num_eq);
+
+ INS_FLD(init_hca_p->srqc_base_addr_h, tmp, tavorprm_qpcbaseaddr_st,
+ srqc_base_addr_h);
+ INS_FLD(init_hca_p->
+ srqc_base_addr_l >> (32 -
+ (MT_BIT_SIZE
+ (tavorprm_qpcbaseaddr_st,
+ srqc_base_addr_l))), tmp,
+ tavorprm_qpcbaseaddr_st, srqc_base_addr_l);
+ INS_FLD(init_hca_p->log_num_of_srq, tmp, tavorprm_qpcbaseaddr_st,
+ log_num_of_srq);
+
+ INS_FLD(init_hca_p->eqpc_base_addr_h, tmp, tavorprm_qpcbaseaddr_st,
+ eqpc_base_addr_h);
+ INS_FLD(init_hca_p->eqpc_base_addr_l, tmp, tavorprm_qpcbaseaddr_st,
+ eqpc_base_addr_l);
+
+ INS_FLD(init_hca_p->eeec_base_addr_h, tmp, tavorprm_qpcbaseaddr_st,
+ eeec_base_addr_h);
+ INS_FLD(init_hca_p->eeec_base_addr_l, tmp, tavorprm_qpcbaseaddr_st,
+ eeec_base_addr_l);
+
+ tmp = p + MT_BYTE_OFFSET(tavorprm_init_hca_st, multicast_parameters);
+
+ INS_FLD(init_hca_p->mc_base_addr_h, tmp, tavorprm_multicastparam_st,
+ mc_base_addr_h);
+ INS_FLD(init_hca_p->mc_base_addr_l, tmp, tavorprm_multicastparam_st,
+ mc_base_addr_l);
+
+ INS_FLD(init_hca_p->log_mc_table_entry_sz, tmp,
+ tavorprm_multicastparam_st, log_mc_table_entry_sz);
+ INS_FLD(init_hca_p->log_mc_table_sz, tmp, tavorprm_multicastparam_st,
+ log_mc_table_sz);
+ INS_FLD(init_hca_p->mc_table_hash_sz, tmp, tavorprm_multicastparam_st,
+ mc_table_hash_sz);
+
+ tmp = p + MT_BYTE_OFFSET(tavorprm_init_hca_st, tpt_parameters);
+
+ INS_FLD(init_hca_p->mpt_base_addr_h, tmp, tavorprm_tptparams_st,
+ mpt_base_adr_h);
+ INS_FLD(init_hca_p->mpt_base_addr_l, tmp, tavorprm_tptparams_st,
+ mpt_base_adr_l);
+ INS_FLD(init_hca_p->log_mpt_sz, tmp, tavorprm_tptparams_st, log_mpt_sz);
+
+ INS_FLD(init_hca_p->mtt_base_addr_h, tmp, tavorprm_tptparams_st,
+ mtt_base_addr_h);
+ INS_FLD(init_hca_p->mtt_base_addr_l, tmp, tavorprm_tptparams_st,
+ mtt_base_addr_l);
+
+ tmp = p + MT_BYTE_OFFSET(tavorprm_init_hca_st, uar_parameters);
+ INS_FLD(tavor_pci_dev.dev.bar[3], tmp, tavorprm_uar_params_st,
+ uar_base_addr_h);
+ INS_FLD(tavor_pci_dev.dev.bar[2] & 0xfff00000, tmp,
+ tavorprm_uar_params_st, uar_base_addr_l);
+
+}
+
+static void prep_sw2hw_mpt_buf(void *buf, __u32 mkey)
+{
+ INS_FLD(1, buf, tavorprm_mpt_st, m_io);
+ INS_FLD(1, buf, tavorprm_mpt_st, lw);
+ INS_FLD(1, buf, tavorprm_mpt_st, lr);
+ INS_FLD(1, buf, tavorprm_mpt_st, pa);
+ INS_FLD(1, buf, tavorprm_mpt_st, r_w);
+
+ INS_FLD(mkey, buf, tavorprm_mpt_st, mem_key);
+ INS_FLD(GLOBAL_PD, buf, tavorprm_mpt_st, pd);
+
+ INS_FLD(virt_to_bus(dev_buffers_p), buf, tavorprm_mpt_st,
+ start_address_l);
+ INS_FLD(memreg_size, buf, tavorprm_mpt_st, reg_wnd_len_l);
+}
+
+static void prep_sw2hw_eq_buf(void *buf, struct eqe_t *eq)
+{
+ memset(buf, 0, MT_STRUCT_SIZE(tavorprm_eqc_st));
+
+ INS_FLD(2, buf, tavorprm_eqc_st, st); /* fired */
+ INS_FLD(virt_to_bus(eq), buf, tavorprm_eqc_st, start_address_l);
+ INS_FLD(LOG2_EQ_SZ, buf, tavorprm_eqc_st, log_eq_size);
+ INS_FLD(UAR_IDX, buf, tavorprm_eqc_st, usr_page);
+ INS_FLD(GLOBAL_PD, buf, tavorprm_eqc_st, pd);
+ INS_FLD(dev_ib_data.mkey, buf, tavorprm_eqc_st, lkey);
+}
+
+static void init_eq_buf(void *eq_buf)
+{
+ int num_eqes = 1 << LOG2_EQ_SZ;
+
+ memset(eq_buf, 0xff, num_eqes * sizeof(struct eqe_t));
+}
+
+static void prep_init_ib_buf(void *buf)
+{
+ __u32 *ptr = (__u32 *) buf;
+
+ ptr[0] = 0x4310;
+ ptr[1] = 1;
+ ptr[2] = 64;
+}
+
+static void prep_sw2hw_cq_buf(void *buf, __u8 eqn, __u32 cqn,
+ union cqe_st *cq_buf)
+{
+ __u32 *ptr = (__u32 *) buf;
+
+ ptr[2] = virt_to_bus(cq_buf);
+ ptr[3] = (LOG2_CQ_SZ << 24) | UAR_IDX;
+ ptr[4] = eqn;
+ ptr[5] = eqn;
+ ptr[6] = dev_ib_data.pd;
+ ptr[7] = dev_ib_data.mkey;
+ ptr[12] = cqn;
+}
+
+static void prep_rst2init_qpee_buf(void *buf, __u32 snd_cqn, __u32 rcv_cqn,
+ __u32 qkey)
+{
+ struct qp_ee_state_tarnisition_st *prm;
+ void *tmp;
+
+ prm = (struct qp_ee_state_tarnisition_st *)buf;
+
+ INS_FLD(3, &prm->ctx, tavorprm_queue_pair_ee_context_entry_st, st); /* service type = UD */
+ INS_FLD(3, &prm->ctx, tavorprm_queue_pair_ee_context_entry_st, pm_state); /* required for UD QP */
+ INS_FLD(UAR_IDX, &prm->ctx, tavorprm_queue_pair_ee_context_entry_st,
+ usr_page);
+ INS_FLD(dev_ib_data.pd, &prm->ctx,
+ tavorprm_queue_pair_ee_context_entry_st, pd);
+ INS_FLD(dev_ib_data.mkey, &prm->ctx,
+ tavorprm_queue_pair_ee_context_entry_st, wqe_lkey);
+ INS_FLD(1, &prm->ctx, tavorprm_queue_pair_ee_context_entry_st, ssc); /* generate send CQE */
+ INS_FLD(1, &prm->ctx, tavorprm_queue_pair_ee_context_entry_st, rsc); /* generate receive CQE */
+ INS_FLD(snd_cqn, &prm->ctx, tavorprm_queue_pair_ee_context_entry_st,
+ cqn_snd);
+ INS_FLD(rcv_cqn, &prm->ctx, tavorprm_queue_pair_ee_context_entry_st,
+ cqn_rcv);
+ INS_FLD(qkey, &prm->ctx, tavorprm_queue_pair_ee_context_entry_st,
+ q_key);
+
+ tmp =
+ (void *)(&prm->ctx) +
+ MT_BYTE_OFFSET(tavorprm_queue_pair_ee_context_entry_st,
+ primary_address_path);
+ INS_FLD(dev_ib_data.port, tmp, tavorprm_address_path_st, port_number);
+
+ INS_FLD(4, &prm->ctx, tavorprm_queue_pair_ee_context_entry_st, mtu);
+ INS_FLD(0xb, &prm->ctx, tavorprm_queue_pair_ee_context_entry_st,
+ msg_max);
+}
+
+static void prep_init2rtr_qpee_buf(void *buf)
+{
+ struct qp_ee_state_tarnisition_st *prm;
+
+ prm = (struct qp_ee_state_tarnisition_st *)buf;
+
+ INS_FLD(4, &prm->ctx, tavorprm_queue_pair_ee_context_entry_st, mtu);
+ INS_FLD(0xb, &prm->ctx, tavorprm_queue_pair_ee_context_entry_st,
+ msg_max);
+}
+
+static void init_av_array()
+{
+ int i;
+
+ dev_ib_data.udav.av_array = dev_buffers_p->av_array;
+ dev_ib_data.udav.udav_next_free = FL_EOL;
+ for (i = 0; i < NUM_AVS; ++i) {
+ dev_ib_data.udav.av_array[i].ud_av.next_free =
+ dev_ib_data.udav.udav_next_free;
+ dev_ib_data.udav.udav_next_free = i;
+ }
+ tprintf("dev_ib_data.udav.udav_next_free=%d", i);
+}
+
+static int setup_hca(__u8 port, void **eq_p)
+{
+ int rc;
+ __u32 key, in_key;
+ __u32 *inprm;
+ struct eqe_t *eq_buf;
+ __u32 event_mask;
+ void *cfg;
+ int ret = 0;
+ __u8 eqn;
+ struct dev_lim_st dev_lim;
+ struct init_hca_st init_hca;
+ __u32 offset, base_h, base_l;
+ const __u32 delta = 0x400000;
+ struct query_fw_st qfw;
+
+ tprintf("called");
+
+ init_dev_data();
+
+ rc = reset_hca();
+ if (rc) {
+ ret = -1;
+ eprintf("");
+ goto exit;
+ } else {
+ tprintf("reset_hca() success");
+ }
+
+ mdelay(1000); /* wait for 1 sec */
+
+ rc = restore_config();
+ if (rc) {
+ ret = -1;
+ eprintf("");
+ goto exit;
+ } else {
+ tprintf("restore_config() success");
+ }
+
+ dev_ib_data.pd = GLOBAL_PD;
+ dev_ib_data.port = port;
+
+ /* execute system enable command */
+ rc = cmd_sys_en();
+ if (rc) {
+ ret = -1;
+ eprintf("");
+ goto exit;
+ } else {
+ tprintf("cmd_sys_en() success");
+ }
+
+ rc= cmd_query_fw(&qfw);
+ if (rc) {
+ ret = -1;
+ eprintf("");
+ goto exit;
+ } else {
+ tprintf("cmd_query_fw() success");
+
+ if (print_info) {
+ printf("FW ver = %d.%d.%d\n",
+ qfw.fw_rev_major,
+ qfw.fw_rev_minor,
+ qfw.fw_rev_subminor);
+ }
+ tprintf("fw_rev_major=%d", qfw.fw_rev_major);
+ tprintf("fw_rev_minor=%d", qfw.fw_rev_minor);
+ tprintf("fw_rev_subminor=%d", qfw.fw_rev_subminor);
+ tprintf("error_buf_start_h=0x%x", qfw.error_buf_start_h);
+ tprintf("error_buf_start_l=0x%x", qfw.error_buf_start_l);
+ tprintf("error_buf_size=%d", qfw.error_buf_size);
+ }
+
+ if (qfw.error_buf_start_h) {
+ eprintf("too high physical address");
+ ret = -1;
+ goto exit;
+ }
+
+ dev_ib_data.error_buf_addr= ioremap(qfw.error_buf_start_l,
+ qfw.error_buf_size*4);
+ dev_ib_data.error_buf_size= qfw.error_buf_size;
+ if (!dev_ib_data.error_buf_addr) {
+ eprintf("");
+ ret = -1;
+ goto exit;
+ }
+
+
+ rc = cmd_query_dev_lim(&dev_lim);
+ if (rc) {
+ ret = -1;
+ eprintf("");
+ goto exit;
+ } else {
+ tprintf("cmd_query_dev_lim() success");
+ tprintf("log2_rsvd_qps=%x", dev_lim.log2_rsvd_qps);
+ tprintf("qpc_entry_sz=%x", dev_lim.qpc_entry_sz);
+ tprintf("log2_rsvd_srqs=%x", dev_lim.log2_rsvd_srqs);
+ tprintf("srq_entry_sz=%x", dev_lim.srq_entry_sz);
+ tprintf("log2_rsvd_ees=%x", dev_lim.log2_rsvd_ees);
+ tprintf("eec_entry_sz=%x", dev_lim.eec_entry_sz);
+ tprintf("log2_rsvd_cqs=%x", dev_lim.log2_rsvd_cqs);
+ tprintf("cqc_entry_sz=%x", dev_lim.cqc_entry_sz);
+ tprintf("log2_rsvd_mtts=%x", dev_lim.log2_rsvd_mtts);
+ tprintf("mtt_entry_sz=%x", dev_lim.mtt_entry_sz);
+ tprintf("log2_rsvd_mrws=%x", dev_lim.log2_rsvd_mrws);
+ tprintf("mpt_entry_sz=%x", dev_lim.mpt_entry_sz);
+ tprintf("eqc_entry_sz=%x", dev_lim.eqc_entry_sz);
+ }
+
+ /* set the qp and cq numbers according
+ to the results of query_dev_lim */
+ dev_ib_data.mads_qp.qpn = (1 << dev_lim.log2_rsvd_qps) +
+ +QPN_BASE + MADS_QPN_SN;
+ dev_ib_data.ipoib_qp.qpn = (1 << dev_lim.log2_rsvd_qps) +
+ +QPN_BASE + IPOIB_QPN_SN;
+
+ dev_ib_data.mads_qp.snd_cq.cqn = (1 << dev_lim.log2_rsvd_cqs) +
+ MADS_SND_CQN_SN;
+ dev_ib_data.mads_qp.rcv_cq.cqn = (1 << dev_lim.log2_rsvd_cqs) +
+ MADS_RCV_CQN_SN;
+
+ dev_ib_data.ipoib_qp.snd_cq.cqn = (1 << dev_lim.log2_rsvd_cqs) +
+ IPOIB_SND_CQN_SN;
+ dev_ib_data.ipoib_qp.rcv_cq.cqn = (1 << dev_lim.log2_rsvd_cqs) +
+ IPOIB_RCV_CQN_SN;
+
+ /* disable SRQ */
+ cfg = (void *)dev_buffers_p->inprm_buf;
+ memset(cfg, 0, MT_STRUCT_SIZE(tavorprm_mod_stat_cfg_st));
+ INS_FLD(1, cfg, tavorprm_mod_stat_cfg_st, srq_m); //cfg->srq_m = 1;
+ rc = cmd_mod_stat_cfg(cfg);
+ if (rc) {
+ ret = -1;
+ eprintf("");
+ goto exit;
+ } else {
+ tprintf("cmd_mod_stat_cfg() success");
+ }
+
+ /* prepare the init_hca params to pass
+ to prep_init_hca_buf */
+ memset(&init_hca, 0, sizeof init_hca);
+ offset = 0;
+ base_h = tavor_pci_dev.dev.bar[5] & 0xfffffff0;
+ base_l = tavor_pci_dev.dev.bar[4] & 0xfffffff0;
+
+ tprintf("base_h=0x%lx, base_l=0x%lx", base_h, base_l);
+
+ init_hca.qpc_base_addr_h = base_h;
+ init_hca.qpc_base_addr_l = base_l + offset;
+ init_hca.log_num_of_qp = dev_lim.log2_rsvd_qps + 1;
+ offset += delta;
+
+ init_hca.eec_base_addr_h = base_h;
+ init_hca.eec_base_addr_l = base_l + offset;
+ init_hca.log_num_of_ee = dev_lim.log2_rsvd_ees;
+ offset += delta;
+
+ init_hca.srqc_base_addr_h = base_h;
+ init_hca.srqc_base_addr_l = base_l + offset;
+ init_hca.log_num_of_srq = dev_lim.log2_rsvd_srqs;
+ offset += delta;
+
+ init_hca.cqc_base_addr_h = base_h;
+ init_hca.cqc_base_addr_l = base_l + offset;
+ init_hca.log_num_of_cq = dev_lim.log2_rsvd_cqs + 1;
+ offset += delta;
+
+ init_hca.eqpc_base_addr_h = base_h;
+ init_hca.eqpc_base_addr_l = base_l + offset;
+ offset += delta;
+
+ init_hca.eeec_base_addr_h = base_h;
+ init_hca.eeec_base_addr_l = base_l + offset;
+ offset += delta;
+
+ init_hca.eqc_base_addr_h = base_h;
+ init_hca.eqc_base_addr_l = base_l + offset;
+ init_hca.log_num_of_eq = LOG2_EQS;
+ offset += delta;
+
+ init_hca.rdb_base_addr_h = base_h;
+ init_hca.rdb_base_addr_l = base_l + offset;
+ offset += delta;
+
+ init_hca.mc_base_addr_h = base_h;
+ init_hca.mc_base_addr_l = base_l + offset;
+ init_hca.log_mc_table_entry_sz = LOG2_MC_ENTRY;
+ init_hca.mc_table_hash_sz = 0;
+ init_hca.log_mc_table_sz = LOG2_MC_GROUPS;
+ offset += delta;
+
+ init_hca.mpt_base_addr_h = base_h;
+ init_hca.mpt_base_addr_l = base_l + offset;
+ init_hca.log_mpt_sz = dev_lim.log2_rsvd_mrws + 1;
+ offset += delta;
+
+ init_hca.mtt_base_addr_h = base_h;
+ init_hca.mtt_base_addr_l = base_l + offset;
+
+ /* this buffer is used for all the commands */
+ inprm = (void *)dev_buffers_p->inprm_buf;
+ /* excute init_hca command */
+ prep_init_hca_buf(&init_hca, inprm);
+
+ rc = cmd_init_hca(inprm, MT_STRUCT_SIZE(tavorprm_init_hca_st));
+ if (rc) {
+ ret = -1;
+ eprintf("");
+ goto undo_sys_en;
+ } else
+ tprintf("cmd_init_hca() success");
+
+ /* register a single memory region which covers
+ 4 GB of the address space which will be used
+ throughout the driver */
+ memset(inprm, 0, SW2HW_MPT_IBUF_SZ);
+ in_key = MKEY_PREFIX + (1 << dev_lim.log2_rsvd_mrws);
+ prep_sw2hw_mpt_buf(inprm, in_key);
+ rc = cmd_sw2hw_mpt(&key, in_key, inprm, SW2HW_MPT_IBUF_SZ);
+ if (rc) {
+ ret = -1;
+ eprintf("");
+ goto undo_init_hca;
+ } else {
+ tprintf("cmd_sw2hw_mpt() success, key=0x%lx", key);
+ }
+ dev_ib_data.mkey = key;
+
+ eqn = EQN;
+ /* allocate a single EQ which will receive
+ all the events */
+ eq_buf = dev_buffers_p->eq_buf;
+ init_eq_buf(eq_buf); /* put in HW ownership */
+ prep_sw2hw_eq_buf(inprm, eq_buf);
+ rc = cmd_sw2hw_eq(SW2HW_EQ_IBUF_SZ);
+ if (rc) {
+ ret = -1;
+ eprintf("");
+ goto undo_sw2hw_mpt;
+ } else
+ tprintf("cmd_sw2hw_eq() success");
+
+ event_mask = (1 << XDEV_EV_TYPE_CQ_COMP) |
+ (1 << XDEV_EV_TYPE_CQ_ERR) |
+ (1 << XDEV_EV_TYPE_LOCAL_WQ_CATAS_ERR) |
+ (1 << XDEV_EV_TYPE_PORT_ERR) |
+ (1 << XDEV_EV_TYPE_LOCAL_WQ_INVALID_REQ_ERR) |
+ (1 << XDEV_EV_TYPE_LOCAL_WQ_ACCESS_VIOL_ERR) |
+ (1 << TAVOR_IF_EV_TYPE_OVERRUN);
+ rc = cmd_map_eq(eqn, event_mask, 1);
+ if (rc) {
+ ret = -1;
+ eprintf("");
+ goto undo_sw2hw_eq;
+ } else
+ tprintf("cmd_map_eq() success");
+
+ dev_ib_data.eq.eqn = eqn;
+ dev_ib_data.eq.eq_buf = eq_buf;
+ dev_ib_data.eq.cons_idx = 0;
+ dev_ib_data.eq.eq_size = 1 << LOG2_EQ_SZ;
+ *eq_p = &dev_ib_data.eq;
+
+ memset(inprm, 0, INIT_IB_IBUF_SZ);
+ prep_init_ib_buf(inprm);
+ rc = cmd_init_ib(port, inprm, INIT_IB_IBUF_SZ);
+ if (rc) {
+ ret = -1;
+ eprintf("");
+ goto undo_sw2hw_eq;
+ } else
+ tprintf("cmd_init_ib() success");
+
+ init_av_array();
+ tprintf("init_av_array() done");
+
+ goto exit;
+
+ undo_sw2hw_eq:
+ rc = cmd_hw2sw_eq(EQN);
+ if (rc) {
+ eprintf("");
+ } else
+ tprintf("cmd_hw2sw_eq() success");
+
+ undo_sw2hw_mpt:
+ rc = cmd_hw2sw_mpt(key);
+ if (rc)
+ eprintf("");
+ else
+ tprintf("cmd_hw2sw_mpt() success key=0x%lx", key);
+
+ undo_init_hca:
+ rc = cmd_close_hca(0);
+ if (rc) {
+ eprintf("");
+ goto undo_sys_en;
+ } else
+ tprintf("cmd_close_hca() success");
+
+ undo_sys_en:
+ rc = cmd_sys_dis();
+ if (rc) {
+ eprintf("");
+ goto undo_sys_en;
+ } else
+ tprintf("cmd_sys_dis() success");
+ goto exit;
+
+ exit:
+ return ret;
+}
+
+static void *get_inprm_buf(void)
+{
+ return dev_buffers_p->inprm_buf;
+}
+
+static void *get_outprm_buf(void)
+{
+ return dev_buffers_p->outprm_buf;
+}
+
+static void *get_send_wqe_buf(void *wqe, __u8 index)
+{
+ struct ud_send_wqe_st *snd_wqe = wqe;
+
+ return bus_to_virt(snd_wqe->mpointer[index].local_addr_l);
+}
+
+static void *get_rcv_wqe_buf(void *wqe, __u8 index)
+{
+ struct recv_wqe_st *rcv_wqe = wqe;
+
+ return bus_to_virt(be32_to_cpu(rcv_wqe->mpointer[index].local_addr_l));
+}
+
+static void modify_av_params(struct ud_av_st *av,
+ __u16 dlid,
+ __u8 g,
+ __u8 sl, __u8 rate, union ib_gid_u *gid, __u32 qpn)
+{
+ memset(&av->av, 0, sizeof av->av);
+ INS_FLD(dev_ib_data.port, &av->av, tavorprm_ud_address_vector_st,
+ port_number);
+ INS_FLD(dev_ib_data.pd, &av->av, tavorprm_ud_address_vector_st, pd);
+ INS_FLD(dlid, &av->av, tavorprm_ud_address_vector_st, rlid);
+ INS_FLD(g, &av->av, tavorprm_ud_address_vector_st, g);
+ INS_FLD(sl, &av->av, tavorprm_ud_address_vector_st, sl);
+ INS_FLD(3, &av->av, tavorprm_ud_address_vector_st, msg);
+
+ if (rate >= 3)
+ INS_FLD(0, &av->av, tavorprm_ud_address_vector_st, max_stat_rate); /* 4x */
+ else
+ INS_FLD(1, &av->av, tavorprm_ud_address_vector_st, max_stat_rate); /* 1x */
+
+ cpu_to_be_buf(&av->av, sizeof(av->av));
+ if (g) {
+ if (gid) {
+ INS_FLD(*((__u32 *) (&gid->raw[0])), &av->av,
+ tavorprm_ud_address_vector_st, rgid_127_96);
+ INS_FLD(*((__u32 *) (&gid->raw[4])), &av->av,
+ tavorprm_ud_address_vector_st, rgid_95_64);
+ INS_FLD(*((__u32 *) (&gid->raw[8])), &av->av,
+ tavorprm_ud_address_vector_st, rgid_63_32);
+ INS_FLD(*((__u32 *) (&gid->raw[12])), &av->av,
+ tavorprm_ud_address_vector_st, rgid_31_0);
+ } else {
+ INS_FLD(0, &av->av, tavorprm_ud_address_vector_st,
+ rgid_127_96);
+ INS_FLD(0, &av->av, tavorprm_ud_address_vector_st,
+ rgid_95_64);
+ INS_FLD(0, &av->av, tavorprm_ud_address_vector_st,
+ rgid_63_32);
+ INS_FLD(0, &av->av, tavorprm_ud_address_vector_st,
+ rgid_31_0);
+ }
+ } else {
+ INS_FLD(0, &av->av, tavorprm_ud_address_vector_st, rgid_127_96);
+ INS_FLD(0, &av->av, tavorprm_ud_address_vector_st, rgid_95_64);
+ INS_FLD(0, &av->av, tavorprm_ud_address_vector_st, rgid_63_32);
+ INS_FLD(2, &av->av, tavorprm_ud_address_vector_st, rgid_31_0);
+ }
+ av->dest_qp = qpn;
+}
+
+static void init_cq_buf(union cqe_st *cq_buf, __u8 num_cqes)
+{
+ memset(cq_buf, 0xff, num_cqes * sizeof cq_buf[0]);
+}
+
+static int post_rcv_buf(struct udqp_st *qp, struct recv_wqe_st *rcv_wqe)
+{
+ struct recv_doorbell_st dbell;
+ int rc;
+ __u32 tmp[2];
+ struct recv_wqe_st *tmp_wqe = (struct recv_wqe_st *)tmp;
+ __u32 *ptr_dst;
+
+ memset(&dbell, 0, sizeof dbell);
+ INS_FLD(sizeof(*rcv_wqe) >> 4, &dbell, tavorprm_receive_doorbell_st,
+ nds);
+ INS_FLD(virt_to_bus(rcv_wqe) >> 6, &dbell, tavorprm_receive_doorbell_st,
+ nda);
+ INS_FLD(qp->qpn, &dbell, tavorprm_receive_doorbell_st, qpn);
+ INS_FLD(1, &dbell, tavorprm_receive_doorbell_st, credits);
+
+ if (qp->last_posted_rcv_wqe) {
+ memcpy(tmp, qp->last_posted_rcv_wqe, sizeof(tmp));
+ be_to_cpu_buf(tmp, sizeof(tmp));
+ INS_FLD(1, tmp_wqe->next, wqe_segment_next_st, dbd);
+ INS_FLD(sizeof(*rcv_wqe) >> 4, tmp_wqe->next,
+ wqe_segment_next_st, nds);
+ INS_FLD(virt_to_bus(rcv_wqe) >> 6, tmp_wqe->next,
+ wqe_segment_next_st, nda_31_6);
+ /* this is not really opcode but since the struct
+ is used for both send and receive, in receive this bit must be 1
+ which coinsides with nopcode */
+ INS_FLD(1, tmp_wqe->next, wqe_segment_next_st, nopcode);
+
+ cpu_to_be_buf(tmp, sizeof(tmp));
+
+ ptr_dst = (__u32 *) (qp->last_posted_rcv_wqe);
+ ptr_dst[0] = tmp[0];
+ ptr_dst[1] = tmp[1];
+ }
+ rc = cmd_post_doorbell(&dbell, POST_RCV_OFFSET);
+ if (!rc) {
+ qp->last_posted_rcv_wqe = rcv_wqe;
+ }
+
+ return rc;
+}
+
+static int post_send_req(void *qph, void *wqeh, __u8 num_gather)
+{
+ struct send_doorbell_st dbell;
+ int rc;
+ struct udqp_st *qp = qph;
+ struct ud_send_wqe_st *snd_wqe = wqeh;
+ struct next_control_seg_st tmp;
+ __u32 *psrc, *pdst;
+ __u32 nds;
+
+ tprintf("snd_wqe=0x%lx, virt_to_bus(snd_wqe)=0x%lx", snd_wqe,
+ virt_to_bus(snd_wqe));
+
+ memset(&dbell, 0, sizeof dbell);
+ INS_FLD(XDEV_NOPCODE_SEND, &dbell, tavorprm_send_doorbell_st, nopcode);
+ INS_FLD(1, &dbell, tavorprm_send_doorbell_st, f);
+ INS_FLD(virt_to_bus(snd_wqe) >> 6, &dbell, tavorprm_send_doorbell_st,
+ nda);
+ nds =
+ (sizeof(snd_wqe->next) + sizeof(snd_wqe->udseg) +
+ sizeof(snd_wqe->mpointer[0]) * num_gather) >> 4;
+ INS_FLD(nds, &dbell, tavorprm_send_doorbell_st, nds);
+ INS_FLD(qp->qpn, &dbell, tavorprm_send_doorbell_st, qpn);
+
+ tprintf("0= %lx", ((__u32 *) ((void *)(&dbell)))[0]);
+ tprintf("1= %lx", ((__u32 *) ((void *)(&dbell)))[1]);
+
+ if (qp->last_posted_snd_wqe) {
+ memcpy(&tmp, &qp->last_posted_snd_wqe->next, sizeof tmp);
+ be_to_cpu_buf(&tmp, sizeof tmp);
+ INS_FLD(1, &tmp, wqe_segment_next_st, dbd);
+ INS_FLD(virt_to_bus(snd_wqe) >> 6, &tmp, wqe_segment_next_st,
+ nda_31_6);
+ INS_FLD(nds, &tmp, wqe_segment_next_st, nds);
+
+ psrc = (__u32 *) (&tmp);
+ pdst = (__u32 *) (&qp->last_posted_snd_wqe->next);
+ pdst[0] = htonl(psrc[0]);
+ pdst[1] = htonl(psrc[1]);
+ }
+
+ rc = cmd_post_doorbell(&dbell, POST_SND_OFFSET);
+ if (!rc) {
+ qp->last_posted_snd_wqe = snd_wqe;
+ }
+
+ return rc;
+}
+
+static int create_mads_qp(void **qp_pp, void **snd_cq_pp, void **rcv_cq_pp)
+{
+ __u8 i;
+ int rc;
+ struct udqp_st *qp;
+
+ qp = &dev_ib_data.mads_qp;
+
+ /* set the pointer to the receive WQEs buffer */
+ qp->rcv_wq = dev_buffers_p->mads_qp_rcv_queue;
+
+ qp->send_buf_sz = MAD_BUF_SZ;
+ qp->rcv_buf_sz = MAD_BUF_SZ;
+
+ qp->recv_wqe_alloc_idx = 0;
+ qp->max_recv_wqes = NUM_MADS_RCV_WQES;
+ qp->recv_wqe_cur_free = NUM_MADS_RCV_WQES;
+
+ /* iterrate through the list */
+ for (i = 0; i < NUM_MADS_RCV_WQES; ++i) {
+ /* clear the WQE */
+ memset(&qp->rcv_wq[i], 0, sizeof(qp->rcv_wq[i]));
+
+ qp->rcv_wq[i].wqe_cont.qp = qp;
+ qp->rcv_bufs[i] = ib_buffers.rcv_mad_buf[i];
+ }
+
+ /* set the pointer to the send WQEs buffer */
+ qp->snd_wq = dev_buffers_p->mads_qp_snd_queue;
+
+ qp->snd_wqe_alloc_idx = 0;
+ qp->max_snd_wqes = NUM_MADS_SND_WQES;
+ qp->snd_wqe_cur_free = NUM_MADS_SND_WQES;
+
+ /* iterrate through the list */
+ for (i = 0; i < NUM_MADS_SND_WQES; ++i) {
+ /* clear the WQE */
+ memset(&qp->snd_wq[i], 0, sizeof(qp->snd_wq[i]));
+
+ /* link the WQE to the free list */
+ qp->snd_wq[i].wqe_cont.qp = qp;
+ qp->snd_bufs[i] = ib_buffers.send_mad_buf[i];
+ }
+
+ /* qp number and cq numbers are already set up */
+ qp->snd_cq.cq_buf = dev_buffers_p->mads_snd_cq_buf;
+ qp->rcv_cq.cq_buf = dev_buffers_p->mads_rcv_cq_buf;
+ qp->snd_cq.num_cqes = NUM_MADS_SND_CQES;
+ qp->rcv_cq.num_cqes = NUM_MADS_RCV_CQES;
+ qp->qkey = GLOBAL_QKEY;
+ rc = create_udqp(qp);
+ if (!rc) {
+ *qp_pp = qp;
+ *snd_cq_pp = &qp->snd_cq;
+ *rcv_cq_pp = &qp->rcv_cq;
+ }
+
+ return rc;
+}
+
+static int create_ipoib_qp(void **qp_pp,
+ void **snd_cq_pp, void **rcv_cq_pp, __u32 qkey)
+{
+ __u8 i;
+ int rc;
+ struct udqp_st *qp;
+ qp = &dev_ib_data.ipoib_qp;
+
+ /* set the pointer to the receive WQEs buffer */
+ qp->rcv_wq = dev_buffers_p->ipoib_qp_rcv_queue;
+
+ qp->rcv_buf_sz = IPOIB_RCV_BUF_SZ;
+
+ qp->recv_wqe_alloc_idx = 0;
+ qp->max_recv_wqes = NUM_IPOIB_RCV_WQES;
+ qp->recv_wqe_cur_free = NUM_IPOIB_RCV_WQES;
+
+ /* iterrate through the list */
+ for (i = 0; i < NUM_IPOIB_RCV_WQES; ++i) {
+ /* clear the WQE */
+ memset(&qp->rcv_wq[i], 0, sizeof(qp->rcv_wq[i]));
+
+ /* update data */
+ qp->rcv_wq[i].wqe_cont.qp = qp;
+ qp->rcv_bufs[i] = ib_buffers.ipoib_rcv_buf[i];
+ tprintf("rcv_buf=%lx", qp->rcv_bufs[i]);
+ }
+
+ /* init send queue WQEs list */
+ /* set the list empty */
+ qp->snd_wqe_alloc_idx = 0;
+ qp->max_snd_wqes = NUM_IPOIB_SND_WQES;
+ qp->snd_wqe_cur_free = NUM_IPOIB_SND_WQES;
+
+ /* set the pointer to the send WQEs buffer */
+ qp->snd_wq = dev_buffers_p->ipoib_qp_snd_queue;
+
+ /* iterrate through the list */
+ for (i = 0; i < NUM_IPOIB_SND_WQES; ++i) {
+ /* clear the WQE */
+ memset(&qp->snd_wq[i], 0, sizeof(qp->snd_wq[i]));
+
+ /* update data */
+ qp->snd_wq[i].wqe_cont.qp = qp;
+ qp->snd_bufs[i] = ib_buffers.send_ipoib_buf[i];
+ qp->send_buf_sz = 4;
+ }
+
+ /* qp number and cq numbers are already set up */
+
+ qp->snd_cq.cq_buf = dev_buffers_p->ipoib_snd_cq_buf;
+ qp->rcv_cq.cq_buf = dev_buffers_p->ipoib_rcv_cq_buf;
+ qp->snd_cq.num_cqes = NUM_IPOIB_SND_CQES;
+ qp->rcv_cq.num_cqes = NUM_IPOIB_RCV_CQES;
+ qp->qkey = qkey;
+ rc = create_udqp(qp);
+ if (!rc) {
+ *qp_pp = qp;
+ *snd_cq_pp = &qp->snd_cq;
+ *rcv_cq_pp = &qp->rcv_cq;
+ }
+
+ return rc;
+}
+
+static int create_udqp(struct udqp_st *qp)
+{
+ int rc, ret = 0;
+ void *inprm;
+ struct recv_wqe_st *rcv_wqe;
+
+ inprm = dev_buffers_p->inprm_buf;
+
+ /* create send CQ */
+ init_cq_buf(qp->snd_cq.cq_buf, qp->snd_cq.num_cqes);
+ qp->snd_cq.cons_idx = 0;
+ memset(inprm, 0, SW2HW_CQ_IBUF_SZ);
+ prep_sw2hw_cq_buf(inprm, dev_ib_data.eq.eqn, qp->snd_cq.cqn,
+ qp->snd_cq.cq_buf);
+ rc = cmd_sw2hw_cq(qp->snd_cq.cqn, inprm, SW2HW_CQ_IBUF_SZ);
+ if (rc) {
+ ret = -1;
+ eprintf("");
+ goto exit;
+ }
+
+ /* create receive CQ */
+ init_cq_buf(qp->rcv_cq.cq_buf, qp->rcv_cq.num_cqes);
+ qp->rcv_cq.cons_idx = 0;
+ memset(inprm, 0, SW2HW_CQ_IBUF_SZ);
+ prep_sw2hw_cq_buf(inprm, dev_ib_data.eq.eqn, qp->rcv_cq.cqn,
+ qp->rcv_cq.cq_buf);
+ rc = cmd_sw2hw_cq(qp->rcv_cq.cqn, inprm, SW2HW_CQ_IBUF_SZ);
+ if (rc) {
+ ret = -1;
+ eprintf("");
+ goto undo_snd_cq;
+ }
+
+ memset(inprm, 0, QPCTX_IBUF_SZ);
+ prep_rst2init_qpee_buf(inprm, qp->snd_cq.cqn, qp->rcv_cq.cqn, qp->qkey);
+ rc = cmd_rst2init_qpee(qp->qpn, inprm, QPCTX_IBUF_SZ);
+ if (rc) {
+ ret = -1;
+ eprintf("");
+ goto undo_rcv_cq;
+ }
+
+ qp->last_posted_rcv_wqe = NULL;
+ qp->last_posted_snd_wqe = NULL;
+
+ /* post all the buffers to the receive queue */
+ while (1) {
+ /* allocate wqe */
+ rcv_wqe = alloc_rcv_wqe(qp);
+ if (!rcv_wqe)
+ break;
+
+ /* post the buffer */
+ rc = post_rcv_buf(qp, rcv_wqe);
+ if (rc) {
+ ret = -1;
+ eprintf("");
+ goto undo_rcv_cq;
+ }
+ }
+
+ memset(inprm, 0, QPCTX_IBUF_SZ);
+ prep_init2rtr_qpee_buf(inprm);
+ rc = cmd_init2rtr_qpee(qp->qpn, inprm, QPCTX_IBUF_SZ);
+ if (rc) {
+ ret = -1;
+ eprintf("");
+ goto undo_rcv_cq;
+ }
+
+ memset(inprm, 0, QPCTX_IBUF_SZ);
+ rc = cmd_rtr2rts_qpee(qp->qpn, inprm, QPCTX_IBUF_SZ);
+ if (rc) {
+ ret = -1;
+ eprintf("");
+ goto undo_rcv_cq;
+ }
+
+ goto exit;
+
+ undo_rcv_cq:
+ rc = cmd_hw2sw_cq(qp->rcv_cq.cqn);
+ if (rc)
+ eprintf("");
+
+ undo_snd_cq:
+ rc = cmd_hw2sw_cq(qp->snd_cq.cqn);
+ if (rc)
+ eprintf("");
+
+ exit:
+ return ret;
+}
+
+static int destroy_udqp(struct udqp_st *qp)
+{
+ int rc;
+
+ rc = cmd_2err_qpee(qp->qpn);
+ if (rc) {
+ eprintf("");
+ return rc;
+ }
+ tprintf("cmd_2err_qpee(0x%lx) success", qp->qpn);
+
+ rc = cmd_2rst_qpee(qp->qpn);
+ if (rc) {
+ eprintf("");
+ return rc;
+ }
+ tprintf("cmd_2rst_qpee(0x%lx) success", qp->qpn);
+
+ rc = cmd_hw2sw_cq(qp->rcv_cq.cqn);
+ if (rc) {
+ eprintf("");
+ return rc;
+ }
+ tprintf("cmd_hw2sw_cq(0x%lx) success", qp->snd_cq.cqn);
+
+ rc = cmd_hw2sw_cq(qp->snd_cq.cqn);
+ if (rc) {
+ eprintf("");
+ return rc;
+ }
+ tprintf("cmd_hw2sw_cq(0x%lx) success", qp->rcv_cq.cqn);
+
+ return rc;
+}
+
+static void prep_send_wqe_buf(void *qph,
+ void *avh,
+ void *wqeh,
+ const void *buf,
+ unsigned int offset, __u16 len, __u8 e)
+{
+ struct udqp_st *qp = qph;
+ struct ud_av_st *av = avh;
+ struct ud_send_wqe_st *wqe = wqeh;
+
+ INS_FLD(e, wqe->next.control, wqe_segment_ctrl_send_st, e);
+ INS_FLD(1, wqe->next.control, wqe_segment_ctrl_send_st, always1);
+
+ wqe->udseg.av_add_h = 0;
+ wqe->udseg.av_add_l = virt_to_bus(&av->av);
+ wqe->udseg.dest_qp = av->dest_qp;
+ wqe->udseg.lkey = dev_ib_data.mkey;
+ wqe->udseg.qkey = qp->qkey;
+
+ if (buf) {
+ memcpy(bus_to_virt(wqe->mpointer[0].local_addr_l) + offset, buf,
+ len);
+ len += offset;
+ }
+ wqe->mpointer[0].byte_count = len;
+ wqe->mpointer[0].lkey = dev_ib_data.mkey;
+
+ cpu_to_be_buf(wqe, sizeof *wqe);
+}
+
+static void *alloc_ud_av(void)
+{
+ u8 next_free;
+
+ if (dev_ib_data.udav.udav_next_free == FL_EOL) {
+ return NULL;
+ }
+
+ next_free = dev_ib_data.udav.udav_next_free;
+ dev_ib_data.udav.udav_next_free =
+ dev_buffers_p->av_array[next_free].ud_av.next_free;
+ tprintf("allocated udav %d", next_free);
+ return &dev_buffers_p->av_array[next_free].ud_av;
+}
+
+static void free_ud_av(void *avh)
+{
+ union ud_av_u *avu;
+ __u8 idx, old_idx;
+ struct ud_av_st *av = avh;
+
+ avu = (union ud_av_u *)av;
+
+ idx = avu - dev_buffers_p->av_array;
+ tprintf("freeing udav idx=%d", idx);
+ old_idx = dev_ib_data.udav.udav_next_free;
+ dev_ib_data.udav.udav_next_free = idx;
+ avu->ud_av.next_free = old_idx;
+}
+
+static int update_cq_cons_idx(struct cq_st *cq)
+{
+ struct cq_dbell_st dbell;
+ int rc;
+
+ memset(&dbell, 0, sizeof dbell);
+ INS_FLD(cq->cqn, &dbell, tavorprm_cq_cmd_doorbell_st, cqn);
+ INS_FLD(CQ_DBELL_CMD_INC_CONS_IDX, &dbell, tavorprm_cq_cmd_doorbell_st,
+ cq_cmd);
+ rc = cmd_post_doorbell(&dbell, CQ_DBELL_OFFSET);
+ return rc;
+}
+
+static int poll_cq(void *cqh, union cqe_st *cqe_p, u8 * num_cqes)
+{
+ union cqe_st cqe;
+ int rc;
+ u32 *ptr;
+ struct cq_st *cq = cqh;
+
+ if (cq->cqn < 0x80 || cq->cqn > 0x83) {
+ eprintf("");
+ return -1;
+ }
+ ptr = (u32 *) (&(cq->cq_buf[cq->cons_idx]));
+ barrier();
+ if ((ptr[7] & 0x80000000) == 0) {
+ cqe = cq->cq_buf[cq->cons_idx];
+ be_to_cpu_buf(&cqe, sizeof(cqe));
+ *cqe_p = cqe;
+ ptr[7] = 0x80000000;
+ barrier();
+ cq->cons_idx = (cq->cons_idx + 1) % cq->num_cqes;
+ rc = update_cq_cons_idx(cq);
+ if (rc) {
+ return rc;
+ }
+ *num_cqes = 1;
+ } else
+ *num_cqes = 0;
+
+ return 0;
+}
+
+static void dev2ib_cqe(struct ib_cqe_st *ib_cqe_p, union cqe_st *cqe_p)
+{
+ __u8 opcode;
+ __u32 wqe_addr_ba;
+
+ opcode =
+ EX_FLD(cqe_p->good_cqe, tavorprm_completion_queue_entry_st, opcode);
+ if (opcode >= CQE_ERROR_OPCODE)
+ ib_cqe_p->is_error = 1;
+ else
+ ib_cqe_p->is_error = 0;
+
+ ib_cqe_p->is_send =
+ EX_FLD(cqe_p->good_cqe, tavorprm_completion_queue_entry_st, s);
+ wqe_addr_ba =
+ EX_FLD(cqe_p->good_cqe, tavorprm_completion_queue_entry_st,
+ wqe_adr) << 6;
+ ib_cqe_p->wqe = bus_to_virt(wqe_addr_ba);
+
+// if (ib_cqe_p->is_send) {
+// be_to_cpu_buf(ib_cqe_p->wqe, sizeof(struct ud_send_wqe_st));
+// }
+// else {
+// be_to_cpu_buf(ib_cqe_p->wqe, sizeof(struct recv_wqe_st));
+// }
+ ib_cqe_p->count =
+ EX_FLD(cqe_p->good_cqe, tavorprm_completion_queue_entry_st,
+ byte_cnt);
+}
+
+static int ib_poll_cq(void *cqh, struct ib_cqe_st *ib_cqe_p, u8 * num_cqes)
+{
+ int rc;
+ union cqe_st cqe;
+ struct cq_st *cq = cqh;
+ __u8 opcode;
+
+ rc = poll_cq(cq, &cqe, num_cqes);
+ if (rc || ((*num_cqes) == 0)) {
+ return rc;
+ }
+
+ dev2ib_cqe(ib_cqe_p, &cqe);
+
+ opcode =
+ EX_FLD(cqe.good_cqe, tavorprm_completion_queue_entry_st, opcode);
+ if (opcode >= CQE_ERROR_OPCODE) {
+ struct ud_send_wqe_st *wqe_p, wqe;
+ __u32 *ptr;
+ unsigned int i;
+
+ wqe_p =
+ bus_to_virt(EX_FLD
+ (cqe.error_cqe,
+ tavorprm_completion_with_error_st,
+ wqe_addr) << 6);
+ eprintf("syndrome=0x%lx",
+ EX_FLD(cqe.error_cqe, tavorprm_completion_with_error_st,
+ syndrome));
+ eprintf("wqe_addr=0x%lx", wqe_p);
+ eprintf("wqe_size=0x%lx",
+ EX_FLD(cqe.error_cqe, tavorprm_completion_with_error_st,
+ wqe_size));
+ eprintf("myqpn=0x%lx",
+ EX_FLD(cqe.error_cqe, tavorprm_completion_with_error_st,
+ myqpn));
+ eprintf("db_cnt=0x%lx",
+ EX_FLD(cqe.error_cqe, tavorprm_completion_with_error_st,
+ db_cnt));
+ memcpy(&wqe, wqe_p, sizeof wqe);
+ be_to_cpu_buf(&wqe, sizeof wqe);
+
+ eprintf("dumping wqe...");
+ ptr = (__u32 *) (&wqe);
+ for (i = 0; i < sizeof wqe; i += 4) {
+ printf("%lx : ", ptr[i >> 2]);
+ }
+
+ }
+
+ return rc;
+}
+
+/* always work on ipoib qp */
+static int add_qp_to_mcast_group(union ib_gid_u mcast_gid, __u8 add)
+{
+ void *mg;
+ __u8 *tmp;
+ int rc;
+ __u16 mgid_hash;
+ void *mgmqp_p;
+
+ tmp = dev_buffers_p->inprm_buf;
+ memcpy(tmp, mcast_gid.raw, 16);
+ be_to_cpu_buf(tmp, 16);
+ rc = cmd_mgid_hash(tmp, &mgid_hash);
+ if (!rc) {
+ mg = (void *)dev_buffers_p->inprm_buf;
+ memset(mg, 0, MT_STRUCT_SIZE(tavorprm_mgm_entry_st));
+ INS_FLD(mcast_gid.as_u32.dw[0], mg, tavorprm_mgm_entry_st, mgid_128_96); // memcpy(&mg->mgid_128_96, &mcast_gid.raw[0], 4);
+ INS_FLD(mcast_gid.as_u32.dw[1], mg, tavorprm_mgm_entry_st, mgid_95_64); // memcpy(&mg->mgid_95_64, &mcast_gid.raw[4], 4);
+ INS_FLD(mcast_gid.as_u32.dw[2], mg, tavorprm_mgm_entry_st, mgid_63_32); //memcpy(&mg->mgid_63_32, &mcast_gid.raw[8], 4);
+ INS_FLD(mcast_gid.as_u32.dw[3], mg, tavorprm_mgm_entry_st, mgid_31_0); //memcpy(&mg->mgid_31_0, &mcast_gid.raw[12], 4);
+ be_to_cpu_buf(mg + MT_BYTE_OFFSET(tavorprm_mgm_entry_st, mgid_128_96), 16); //be_to_cpu_buf(&mg->mgid_128_96, 16);
+ mgmqp_p = mg + MT_BYTE_OFFSET(tavorprm_mgm_entry_st, mgmqp_0);
+ INS_FLD(dev_ib_data.ipoib_qp.qpn, mgmqp_p, tavorprm_mgmqp_st, qpn_i); //mg->mgmqp[0].qpn = dev_ib_data.ipoib_qp.qpn;
+ INS_FLD(add, mgmqp_p, tavorprm_mgmqp_st, qi); //mg->mgmqp[0].valid = add ? 1 : 0;
+ rc = cmd_write_mgm(mg, mgid_hash);
+ }
+ return rc;
+}
+
+static int clear_interrupt(void)
+{
+ __u32 ecr;
+ int ret = 0;
+
+ if (gw_read_cr(0x80704, &ecr)) {
+ eprintf("");
+ } else {
+ if (ecr) {
+ ret = 1;
+ }
+ }
+ gw_write_cr(0xf00d8, 0x80000000); /* clear int */
+ gw_write_cr(0x8070c, 0xffffffff);
+
+ return ret;
+}
+
+static struct ud_send_wqe_st *alloc_send_wqe(udqp_t qph)
+{
+ struct udqp_st *qp = qph;
+ __u8 new_entry;
+ struct ud_send_wqe_st *wqe;
+
+ if (qp->snd_wqe_cur_free == 0) {
+ return NULL;
+ }
+ new_entry = qp->snd_wqe_alloc_idx;
+
+ wqe = &qp->snd_wq[new_entry].wqe;
+ qp->snd_wqe_cur_free--;
+ qp->snd_wqe_alloc_idx = (qp->snd_wqe_alloc_idx + 1) % qp->max_snd_wqes;
+
+ memset(wqe, 0, sizeof *wqe);
+
+ wqe->mpointer[0].local_addr_l = virt_to_bus(qp->snd_bufs[new_entry]);
+
+ return wqe;
+}
+
+/*
+ * alloc_rcv_wqe
+ *
+ * Note: since we work directly on the work queue, wqes
+ * are left in big endian
+ */
+static struct recv_wqe_st *alloc_rcv_wqe(struct udqp_st *qp)
+{
+ __u8 new_entry;
+ struct recv_wqe_st *wqe;
+
+ if (qp->recv_wqe_cur_free == 0) {
+ return NULL;
+ }
+
+ new_entry = qp->recv_wqe_alloc_idx;
+ wqe = &qp->rcv_wq[new_entry].wqe;
+
+ qp->recv_wqe_cur_free--;
+ qp->recv_wqe_alloc_idx =
+ (qp->recv_wqe_alloc_idx + 1) % qp->max_recv_wqes;
+
+ memset(wqe, 0, sizeof *wqe);
+
+ /* GRH is always required */
+ wqe->mpointer[0].local_addr_h = 0;
+ wqe->mpointer[0].local_addr_l = virt_to_bus(qp->rcv_bufs[new_entry]);
+ wqe->mpointer[0].lkey = dev_ib_data.mkey;
+ wqe->mpointer[0].byte_count = GRH_SIZE;
+
+ wqe->mpointer[1].local_addr_h = 0;
+ wqe->mpointer[1].local_addr_l =
+ virt_to_bus(qp->rcv_bufs[new_entry] + GRH_SIZE);
+ wqe->mpointer[1].lkey = dev_ib_data.mkey;
+ wqe->mpointer[1].byte_count = qp->rcv_buf_sz;
+
+ tprintf("rcv_buf=%lx\n", qp->rcv_bufs[new_entry]);
+
+ /* we do it only on the data segment since the control
+ segment is always owned by HW */
+ cpu_to_be_buf(wqe, sizeof *wqe);
+
+// tprintf("alloc wqe= 0x%x", wqe);
+ return wqe;
+}
+
+static int free_send_wqe(struct ud_send_wqe_st *wqe)
+{
+ union ud_send_wqe_u *wqe_u;
+ struct udqp_st *qp;
+
+ wqe_u = (union ud_send_wqe_u *)wqe;
+ qp = wqe_u->wqe_cont.qp;
+
+ if (qp->snd_wqe_cur_free >= qp->max_snd_wqes) {
+ return -1;
+ }
+
+ qp->snd_wqe_cur_free++;
+
+ return 0;
+}
+
+static int free_rcv_wqe(struct recv_wqe_st *wqe)
+{
+ union recv_wqe_u *wqe_u;
+ struct udqp_st *qp;
+
+ wqe_u = (union recv_wqe_u *)wqe;
+ qp = wqe_u->wqe_cont.qp;
+
+ if (qp->recv_wqe_cur_free >= qp->max_recv_wqes) {
+ return -1;
+ }
+
+ qp->recv_wqe_cur_free++;
+
+ return 0;
+}
+
+static int free_wqe(void *wqe)
+{
+ int rc = 0;
+ struct recv_wqe_st *rcv_wqe;
+
+// tprintf("free wqe= 0x%x", wqe);
+ if ((wqe >= (void *)(dev_ib_data.ipoib_qp.rcv_wq)) &&
+ (wqe <
+ (void *)(&dev_ib_data.ipoib_qp.rcv_wq[NUM_IPOIB_RCV_WQES]))) {
+ /* ipoib receive wqe */
+ free_rcv_wqe(wqe);
+ rcv_wqe = alloc_rcv_wqe(&dev_ib_data.ipoib_qp);
+ if (rcv_wqe) {
+ rc = post_rcv_buf(&dev_ib_data.ipoib_qp, rcv_wqe);
+ if (rc) {
+ eprintf("");
+ }
+ }
+ } else if (wqe >= (void *)(dev_ib_data.ipoib_qp.snd_wq) &&
+ wqe <
+ (void *)(&dev_ib_data.ipoib_qp.snd_wq[NUM_IPOIB_SND_WQES])) {
+ /* ipoib send wqe */
+ free_send_wqe(wqe);
+ } else if (wqe >= (void *)(dev_ib_data.mads_qp.rcv_wq) &&
+ wqe <
+ (void *)(&dev_ib_data.mads_qp.rcv_wq[NUM_MADS_RCV_WQES])) {
+ /* mads receive wqe */
+ free_rcv_wqe(wqe);
+ rcv_wqe = alloc_rcv_wqe(&dev_ib_data.mads_qp);
+ if (rcv_wqe) {
+ rc = post_rcv_buf(&dev_ib_data.mads_qp, rcv_wqe);
+ if (rc) {
+ eprintf("");
+ }
+ }
+ } else if (wqe >= (void *)(dev_ib_data.mads_qp.snd_wq) &&
+ wqe <
+ (void *)(&dev_ib_data.mads_qp.snd_wq[NUM_MADS_SND_WQES])) {
+ /* mads send wqe */
+ free_send_wqe(wqe);
+ } else {
+ rc = -1;
+ eprintf("");
+ }
+
+ return rc;
+}
+
+static int update_eq_cons_idx(struct eq_st *eq)
+{
+ struct eq_dbell_st dbell;
+ int rc;
+
+ memset(&dbell, 0, sizeof dbell);
+ INS_FLD(dev_ib_data.eq.eqn, &dbell, tavorprm_eq_cmd_doorbell_st, eqn);
+ INS_FLD(EQ_DBELL_CMD_SET_CONS_IDX, &dbell, tavorprm_eq_cmd_doorbell_st,
+ eq_cmd);
+ INS_FLD(eq->cons_idx, &dbell, tavorprm_eq_cmd_doorbell_st, eq_param);
+ rc = cmd_post_doorbell(&dbell, EQ_DBELL_OFFSET);
+
+ return rc;
+}
+
+static void dev2ib_eqe(struct ib_eqe_st *ib_eqe_p, void *eqe_p)
+{
+ void *tmp;
+
+ ib_eqe_p->event_type =
+ EX_FLD(eqe_p, tavorprm_event_queue_entry_st, event_type);
+
+ tmp = eqe_p + MT_BYTE_OFFSET(tavorprm_event_queue_entry_st, event_data);
+ ib_eqe_p->cqn = EX_FLD(tmp, tavorprm_completion_event_st, cqn);
+}
+
+static int poll_eq(struct ib_eqe_st *ib_eqe_p, __u8 * num_eqes)
+{
+ struct eqe_t eqe;
+ __u8 owner;
+ int rc;
+ __u32 *ptr;
+ struct eq_st *eq = &dev_ib_data.eq;
+
+ ptr = (__u32 *) (&(eq->eq_buf[eq->cons_idx]));
+ tprintf("cons)idx=%d, addr(eqe)=%x, val=0x%x", eq->cons_idx, virt_to_bus(ptr), ptr[7]);
+ owner = (ptr[7] & 0x80000000) ? OWNER_HW : OWNER_SW;
+ if (owner == OWNER_SW) {
+ tprintf("got eqe");
+ eqe = eq->eq_buf[eq->cons_idx];
+ be_to_cpu_buf(&eqe, sizeof(eqe));
+ dev2ib_eqe(ib_eqe_p, &eqe);
+ ptr[7] |= 0x80000000;
+ eq->eq_buf[eq->cons_idx] = eqe;
+ eq->cons_idx = (eq->cons_idx + 1) % eq->eq_size;
+ rc = update_eq_cons_idx(eq);
+ if (rc) {
+ return -1;
+ }
+ *num_eqes = 1;
+ } else {
+ *num_eqes = 0;
+ }
+ return 0;
+}
+
+static int ib_device_close(void)
+{
+ iounmap(tavor_pci_dev.uar);
+ iounmap(tavor_pci_dev.cr_space);
+ iounmap(dev_ib_data.error_buf_addr);
+ return 0;
+}
+
+static __u32 dev_get_qpn(void *qph)
+{
+ struct udqp_st *qp = qph;
+
+ return qp->qpn;
+}
+
+static void dev_post_dbell(void *dbell, __u32 offset)
+{
+ __u32 *ptr;
+ unsigned long address;
+
+ ptr = dbell;
+ tprintf("ptr[0]= 0x%lx", ptr[0]);
+ tprintf("ptr[1]= 0x%lx", ptr[1]);
+ address = (unsigned long)(tavor_pci_dev.uar) + offset;
+ tprintf("va=0x%lx pa=0x%lx", address,
+ virt_to_bus((const void *)address));
+ writel(htonl(ptr[0]), tavor_pci_dev.uar + offset);
+ barrier();
+ address += 4;
+ tprintf("va=0x%lx pa=0x%lx", address,
+ virt_to_bus((const void *)address));
+ writel(htonl(ptr[1]), tavor_pci_dev.uar + offset + 4);
+}
+
+
diff --git a/src/drivers/net/mlx_ipoib/ib_mt25218.c b/src/drivers/net/mlx_ipoib/ib_mt25218.c
new file mode 100644
index 000000000..11b25d491
--- /dev/null
+++ b/src/drivers/net/mlx_ipoib/ib_mt25218.c
@@ -0,0 +1,1929 @@
+/*
+ This software is available to you under a choice of one of two
+ licenses. You may choose to be licensed under the terms of the GNU
+ General Public License (GPL) Version 2, available at
+ <http://www.fsf.org/copyleft/gpl.html>, or the OpenIB.org BSD
+ license, available in the LICENSE.TXT file accompanying this
+ software. These details are also available at
+ <http://openib.org/license.html>.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+
+ Copyright (c) 2004 Mellanox Technologies Ltd. All rights reserved.
+*/
+
+#include "mt25218.h"
+#include "ib_driver.h"
+#include "pci.h"
+
+#define MOD_INC(counter, max_count) (counter) = ((counter)+1) & ((max_count) - 1)
+
+#define breakpoint {volatile __u32 *p=(__u32 *)0x1234;printf("breakpoint\n");do {} while((*p) != 0x1234);}
+
+#define WRITE_BYTE_VOL(addr, off, val) \
+ do { \
+ (*((volatile __u8 *)(((volatile __u8 *)(addr)) + off))) = (val); \
+ } while(0)
+
+#define WRITE_WORD_VOL(addr, off, val) \
+ do { \
+ (*((volatile __u16 *)(((volatile __u8 *)(addr)) + off))) = (val); \
+ } while(0)
+
+#define WRITE_DWORD_VOL(addr, off, val) \
+ do { \
+ (*((volatile __u32 *)(((volatile __u8 *)(addr)) + off))) = (val); \
+ } while(0)
+
+struct device_buffers_st {
+ /* inprm and outprm do not have alignnemet constraint sice that
+ is acheived programatically */
+ u8 inprm_buf[INPRM_BUF_SZ];
+ u8 outprm_buf[OUTPRM_BUF_SZ];
+ union recv_wqe_u mads_qp_rcv_queue[NUM_MADS_RCV_WQES]
+ __attribute__ ((aligned(RECV_WQE_U_ALIGN)));
+ union recv_wqe_u ipoib_qp_rcv_queue[NUM_IPOIB_RCV_WQES]
+ __attribute__ ((aligned(RECV_WQE_U_ALIGN)));
+ union ud_send_wqe_u mads_qp_snd_queue[NUM_MADS_SND_WQES]
+ __attribute__ ((aligned(UD_SEND_WQE_U_ALIGN)));
+ union ud_send_wqe_u ipoib_qp_snd_queue[NUM_IPOIB_SND_WQES]
+ __attribute__ ((aligned(UD_SEND_WQE_U_ALIGN)));
+ struct eqe_t eq_buf[1 << LOG2_EQ_SZ]
+ __attribute__ ((aligned(sizeof(struct eqe_t))));
+ union cqe_st mads_snd_cq_buf[NUM_MADS_SND_CQES]
+ __attribute__ ((aligned(sizeof(union cqe_st))));
+ union cqe_st ipoib_snd_cq_buf[NUM_IPOIB_SND_CQES]
+ __attribute__ ((aligned(sizeof(union cqe_st))));
+ union cqe_st mads_rcv_cq_buf[NUM_MADS_RCV_CQES]
+ __attribute__ ((aligned(sizeof(union cqe_st))));
+ union cqe_st ipoib_rcv_cq_buf[NUM_IPOIB_RCV_CQES]
+ __attribute__ ((aligned(sizeof(union cqe_st))));
+ union ud_av_u av_array[NUM_AVS];
+} __attribute__ ((packed));
+
+#define STRUCT_ALIGN_SZ 4096
+#define SRC_BUF_SZ (sizeof(struct device_buffers_st) + STRUCT_ALIGN_SZ - 1)
+
+/* the following must be kept in this order
+ for the memory region to cover the buffers */
+static u8 src_buf[SRC_BUF_SZ];
+static struct ib_buffers_st ib_buffers;
+static __u32 memreg_size;
+/* end of order constraint */
+
+struct phys_mem_desc_st {
+ unsigned long base;
+ unsigned long offset;
+};
+
+static struct phys_mem_desc_st phys_mem;
+
+static struct dev_pci_struct memfree_pci_dev;
+static struct device_buffers_st *dev_buffers_p;
+static struct device_ib_data_st dev_ib_data;
+
+static int gw_write_cr(__u32 addr, __u32 data)
+{
+ writel(htonl(data), memfree_pci_dev.cr_space + addr);
+ return 0;
+}
+
+static int gw_read_cr(__u32 addr, __u32 * result)
+{
+ *result = ntohl(readl(memfree_pci_dev.cr_space + addr));
+ return 0;
+}
+
+static int reset_hca(void)
+{
+ return gw_write_cr(MEMFREE_RESET_OFFSET, 1);
+}
+
+static int ib_device_init(struct pci_device *dev)
+{
+ int i;
+ int rc;
+
+ tprintf("");
+
+ memset(&dev_ib_data, 0, sizeof dev_ib_data);
+
+ /* save bars */
+ tprintf("bus=%d devfn=0x%x", dev->bus, dev->devfn);
+ for (i = 0; i < 6; ++i) {
+ memfree_pci_dev.dev.bar[i] =
+ pci_bar_start(dev, PCI_BASE_ADDRESS_0 + (i << 2));
+ tprintf("bar[%d]= 0x%08lx", i, memfree_pci_dev.dev.bar[i]);
+ }
+
+ tprintf("");
+ /* save config space */
+ for (i = 0; i < 64; ++i) {
+ rc = pci_read_config_dword(dev, i << 2,
+ &memfree_pci_dev.dev.
+ dev_config_space[i]);
+ if (rc) {
+ eprintf("");
+ return rc;
+ }
+ tprintf("config[%d]= 0x%08lx", i << 2,
+ memfree_pci_dev.dev.dev_config_space[i]);
+ }
+
+ tprintf("");
+ memfree_pci_dev.dev.dev = dev;
+
+ /* map cr-space */
+ memfree_pci_dev.cr_space =
+ ioremap(memfree_pci_dev.dev.bar[0], 0x100000);
+ if (!memfree_pci_dev.cr_space) {
+ eprintf("");
+ return -1;
+ }
+
+ /* map uar */
+ memfree_pci_dev.uar =
+ ioremap(memfree_pci_dev.dev.bar[2] + UAR_IDX * 0x1000, 0x1000);
+ if (!memfree_pci_dev.uar) {
+ eprintf("");
+ return -1;
+ }
+ tprintf("uar_base (pa:va) = 0x%lx 0x%lx",
+ memfree_pci_dev.dev.bar[2] + UAR_IDX * 0x1000,
+ memfree_pci_dev.uar);
+
+ tprintf("");
+
+ return 0;
+}
+
+static inline unsigned long lalign(unsigned long buf, unsigned long align)
+{
+ return (unsigned long)((buf + align - 1) &
+ (~(((unsigned long)align) - 1)));
+}
+
+static int init_dev_data(void)
+{
+ unsigned long tmp;
+ unsigned long reserve_size = 32 * 1024 * 1024;
+
+ tmp = lalign(virt_to_bus(src_buf), STRUCT_ALIGN_SZ);
+
+ dev_buffers_p = bus_to_virt(tmp);
+ memreg_size = (__u32) (&memreg_size) - (__u32) dev_buffers_p;
+ tprintf("src_buf=0x%lx, dev_buffers_p=0x%lx, memreg_size=0x%x", src_buf,
+ dev_buffers_p, memreg_size);
+
+ tprintf("inprm: va=0x%lx, pa=0x%lx", dev_buffers_p->inprm_buf,
+ virt_to_bus(dev_buffers_p->inprm_buf));
+ tprintf("outprm: va=0x%lx, pa=0x%lx", dev_buffers_p->outprm_buf,
+ virt_to_bus(dev_buffers_p->outprm_buf));
+
+ phys_mem.base =
+ (virt_to_phys(_text) - reserve_size) & (~(reserve_size - 1));
+
+ phys_mem.offset = 0;
+
+ return 0;
+}
+
+static int restore_config(void)
+{
+ int i;
+ int rc;
+
+ for (i = 0; i < 64; ++i) {
+ if (i != 22 && i != 23) {
+ rc = pci_write_config_dword(memfree_pci_dev.dev.dev,
+ i << 2,
+ memfree_pci_dev.dev.
+ dev_config_space[i]);
+ if (rc) {
+ return rc;
+ }
+ }
+ }
+ return 0;
+}
+
+static void prep_init_hca_buf(struct init_hca_st *init_hca_p, void *buf)
+{
+ unsigned long ptr;
+ __u8 shift;
+
+ memset(buf, 0, MT_STRUCT_SIZE(arbelprm_init_hca_st));
+
+ ptr = (unsigned long)buf +
+ MT_BYTE_OFFSET(arbelprm_init_hca_st,
+ qpc_eec_cqc_eqc_rdb_parameters);
+
+ shift = 32 - MT_BIT_SIZE(arbelprm_qpcbaseaddr_st, qpc_base_addr_l);
+ INS_FLD(init_hca_p->qpc_base_addr_h, ptr, arbelprm_qpcbaseaddr_st,
+ qpc_base_addr_h);
+ INS_FLD(init_hca_p->qpc_base_addr_l >> shift, ptr,
+ arbelprm_qpcbaseaddr_st, qpc_base_addr_l);
+ INS_FLD(init_hca_p->log_num_of_qp, ptr, arbelprm_qpcbaseaddr_st,
+ log_num_of_qp);
+
+ shift = 32 - MT_BIT_SIZE(arbelprm_qpcbaseaddr_st, eec_base_addr_l);
+ INS_FLD(init_hca_p->eec_base_addr_h, ptr, arbelprm_qpcbaseaddr_st,
+ eec_base_addr_h);
+ INS_FLD(init_hca_p->eec_base_addr_l >> shift, ptr,
+ arbelprm_qpcbaseaddr_st, eec_base_addr_l);
+ INS_FLD(init_hca_p->log_num_of_ee, ptr, arbelprm_qpcbaseaddr_st,
+ log_num_of_ee);
+
+ shift = 32 - MT_BIT_SIZE(arbelprm_qpcbaseaddr_st, srqc_base_addr_l);
+ INS_FLD(init_hca_p->srqc_base_addr_h, ptr, arbelprm_qpcbaseaddr_st,
+ srqc_base_addr_h);
+ INS_FLD(init_hca_p->srqc_base_addr_l >> shift, ptr,
+ arbelprm_qpcbaseaddr_st, srqc_base_addr_l);
+ INS_FLD(init_hca_p->log_num_of_srq, ptr, arbelprm_qpcbaseaddr_st,
+ log_num_of_srq);
+
+ shift = 32 - MT_BIT_SIZE(arbelprm_qpcbaseaddr_st, cqc_base_addr_l);
+ INS_FLD(init_hca_p->cqc_base_addr_h, ptr, arbelprm_qpcbaseaddr_st,
+ cqc_base_addr_h);
+ INS_FLD(init_hca_p->cqc_base_addr_l >> shift, ptr,
+ arbelprm_qpcbaseaddr_st, cqc_base_addr_l);
+ INS_FLD(init_hca_p->log_num_of_cq, ptr, arbelprm_qpcbaseaddr_st,
+ log_num_of_cq);
+
+ INS_FLD(init_hca_p->eqpc_base_addr_h, ptr, arbelprm_qpcbaseaddr_st,
+ eqpc_base_addr_h);
+ INS_FLD(init_hca_p->eqpc_base_addr_l, ptr, arbelprm_qpcbaseaddr_st,
+ eqpc_base_addr_l);
+
+ INS_FLD(init_hca_p->eeec_base_addr_h, ptr, arbelprm_qpcbaseaddr_st,
+ eeec_base_addr_h);
+ INS_FLD(init_hca_p->eeec_base_addr_l, ptr, arbelprm_qpcbaseaddr_st,
+ eeec_base_addr_l);
+
+ shift = 32 - MT_BIT_SIZE(arbelprm_qpcbaseaddr_st, eqc_base_addr_l);
+ INS_FLD(init_hca_p->eqc_base_addr_h, ptr, arbelprm_qpcbaseaddr_st,
+ eqc_base_addr_h);
+ INS_FLD(init_hca_p->eqc_base_addr_l >> shift, ptr,
+ arbelprm_qpcbaseaddr_st, eqc_base_addr_l);
+ INS_FLD(init_hca_p->log_num_of_eq, ptr, arbelprm_qpcbaseaddr_st,
+ log_num_eq);
+
+ INS_FLD(init_hca_p->rdb_base_addr_h, ptr, arbelprm_qpcbaseaddr_st,
+ rdb_base_addr_h);
+ INS_FLD(init_hca_p->rdb_base_addr_l, ptr, arbelprm_qpcbaseaddr_st,
+ rdb_base_addr_l);
+
+ ptr = (unsigned long)buf +
+ MT_BYTE_OFFSET(arbelprm_init_hca_st, multicast_parameters);
+
+ INS_FLD(init_hca_p->mc_base_addr_h, ptr, arbelprm_multicastparam_st,
+ mc_base_addr_h);
+ INS_FLD(init_hca_p->mc_base_addr_l, ptr, arbelprm_multicastparam_st,
+ mc_base_addr_l);
+ INS_FLD(init_hca_p->log_mc_table_entry_sz, ptr,
+ arbelprm_multicastparam_st, log_mc_table_entry_sz);
+ INS_FLD(init_hca_p->mc_table_hash_sz, ptr, arbelprm_multicastparam_st,
+ mc_table_hash_sz);
+ INS_FLD(init_hca_p->log_mc_table_sz, ptr, arbelprm_multicastparam_st,
+ log_mc_table_sz);
+
+ ptr = (unsigned long)buf +
+ MT_BYTE_OFFSET(arbelprm_init_hca_st, tpt_parameters);
+
+ INS_FLD(init_hca_p->mpt_base_addr_h, ptr, arbelprm_tptparams_st,
+ mpt_base_adr_h);
+ INS_FLD(init_hca_p->mpt_base_addr_l, ptr, arbelprm_tptparams_st,
+ mpt_base_adr_l);
+ INS_FLD(init_hca_p->log_mpt_sz, ptr, arbelprm_tptparams_st, log_mpt_sz);
+ INS_FLD(init_hca_p->mtt_base_addr_h, ptr, arbelprm_tptparams_st,
+ mtt_base_addr_h);
+ INS_FLD(init_hca_p->mtt_base_addr_l, ptr, arbelprm_tptparams_st,
+ mtt_base_addr_l);
+
+ ptr = (unsigned long)buf +
+ MT_BYTE_OFFSET(arbelprm_init_hca_st, uar_parameters);
+
+ INS_FLD(init_hca_p->log_max_uars, ptr, arbelprm_uar_params_st,
+ log_max_uars);
+
+}
+
+static void prep_sw2hw_mpt_buf(void *buf, __u32 mkey)
+{
+ INS_FLD(1, buf, arbelprm_mpt_st, lw);
+ INS_FLD(1, buf, arbelprm_mpt_st, lr);
+ INS_FLD(1, buf, arbelprm_mpt_st, pa);
+ INS_FLD(1, buf, arbelprm_mpt_st, r_w);
+ INS_FLD(mkey, buf, arbelprm_mpt_st, mem_key);
+ INS_FLD(GLOBAL_PD, buf, arbelprm_mpt_st, pd);
+ INS_FLD(virt_to_bus(dev_buffers_p), buf, arbelprm_mpt_st,
+ start_address_l);
+ INS_FLD(memreg_size, buf, arbelprm_mpt_st, reg_wnd_len_l);
+}
+
+static void prep_sw2hw_eq_buf(void *buf, struct eqe_t *eq_buf)
+{
+ memset(buf, 0, MT_STRUCT_SIZE(arbelprm_eqc_st));
+
+ INS_FLD(0xa, buf, arbelprm_eqc_st, st); /* fired */
+ INS_FLD(virt_to_bus(eq_buf), buf, arbelprm_eqc_st, start_address_l);
+ INS_FLD(LOG2_EQ_SZ, buf, arbelprm_eqc_st, log_eq_size);
+ INS_FLD(GLOBAL_PD, buf, arbelprm_eqc_st, pd);
+ INS_FLD(dev_ib_data.mkey, buf, arbelprm_eqc_st, lkey);
+}
+
+static void init_eq_buf(void *eq_buf)
+{
+ struct eqe_t *eq = eq_buf;
+ int i, num_eqes = 1 << LOG2_EQ_SZ;
+
+ memset(eq, 0, num_eqes * sizeof eq[0]);
+ for (i = 0; i < num_eqes; ++i)
+ WRITE_BYTE_VOL(&eq[i], EQE_OWNER_OFFSET, EQE_OWNER_VAL_HW);
+}
+
+static void prep_init_ib_buf(void *buf)
+{
+ memset(buf, 0, MT_STRUCT_SIZE(arbelprm_init_ib_st));
+
+ INS_FLD(MTU_2048, buf, arbelprm_init_ib_st, mtu_cap);
+ INS_FLD(3, buf, arbelprm_init_ib_st, port_width_cap);
+ INS_FLD(1, buf, arbelprm_init_ib_st, vl_cap);
+ INS_FLD(1, buf, arbelprm_init_ib_st, max_gid);
+ INS_FLD(64, buf, arbelprm_init_ib_st, max_pkey);
+}
+
+static void prep_sw2hw_cq_buf(void *buf, __u8 eqn,
+ __u32 cqn,
+ union cqe_st *cq_buf,
+ __u32 cq_ci_db_record, __u32 cq_state_db_record)
+{
+ memset(buf, 0, MT_STRUCT_SIZE(arbelprm_completion_queue_context_st));
+
+ INS_FLD(0xA, buf, arbelprm_completion_queue_context_st, st);
+ INS_FLD(virt_to_bus(cq_buf), buf, arbelprm_completion_queue_context_st,
+ start_address_l);
+ INS_FLD(LOG2_CQ_SZ, buf, arbelprm_completion_queue_context_st,
+ log_cq_size);
+ INS_FLD(dev_ib_data.uar_idx, buf, arbelprm_completion_queue_context_st,
+ usr_page);
+ INS_FLD(eqn, buf, arbelprm_completion_queue_context_st, c_eqn);
+ INS_FLD(GLOBAL_PD, buf, arbelprm_completion_queue_context_st, pd);
+ INS_FLD(dev_ib_data.mkey, buf, arbelprm_completion_queue_context_st,
+ l_key);
+ INS_FLD(cqn, buf, arbelprm_completion_queue_context_st, cqn);
+ INS_FLD(cq_ci_db_record, buf, arbelprm_completion_queue_context_st,
+ cq_ci_db_record);
+ INS_FLD(cq_state_db_record, buf, arbelprm_completion_queue_context_st,
+ cq_state_db_record);
+}
+
+static void prep_rst2init_qpee_buf(void *buf,
+ __u32 snd_cqn,
+ __u32 rcv_cqn,
+ __u32 qkey,
+ __u32 log_rq_size,
+ __u32 log_rq_stride,
+ __u32 log_sq_size,
+ __u32 log_sq_stride,
+ __u32 snd_wqe_base_adr_l,
+ __u32 snd_db_record_index,
+ __u32 rcv_wqe_base_adr_l,
+ __u32 rcv_db_record_index)
+{
+ void *tmp;
+ int shift;
+ struct qp_ee_state_tarnisition_st *prm = buf;
+
+ memset(buf, 0, sizeof *prm);
+
+ tprintf("snd_cqn=0x%lx", snd_cqn);
+ tprintf("rcv_cqn=0x%lx", rcv_cqn);
+ tprintf("qkey=0x%lx", qkey);
+ tprintf("log_rq_size=0x%lx", log_rq_size);
+ tprintf("log_rq_stride=0x%lx", log_rq_stride);
+ tprintf("log_sq_size=0x%lx", log_sq_size);
+ tprintf("log_sq_stride=0x%lx", log_sq_stride);
+ tprintf("snd_wqe_base_adr_l=0x%lx", snd_wqe_base_adr_l);
+ tprintf("snd_db_record_index=0x%lx", snd_db_record_index);
+ tprintf("rcv_wqe_base_adr_l=0x%lx", rcv_wqe_base_adr_l);
+ tprintf("rcv_db_record_index=0x%lx", rcv_db_record_index);
+
+ tmp = &prm->ctx;
+ INS_FLD(TS_UD, tmp, arbelprm_queue_pair_ee_context_entry_st, st);
+ INS_FLD(PM_STATE_MIGRATED, tmp, arbelprm_queue_pair_ee_context_entry_st,
+ pm_state);
+ INS_FLD(1, tmp, arbelprm_queue_pair_ee_context_entry_st, de);
+ INS_FLD(MTU_2048, tmp, arbelprm_queue_pair_ee_context_entry_st, mtu);
+ INS_FLD(11, tmp, arbelprm_queue_pair_ee_context_entry_st, msg_max);
+ INS_FLD(log_rq_size, tmp, arbelprm_queue_pair_ee_context_entry_st,
+ log_rq_size);
+ INS_FLD(log_rq_stride, tmp, arbelprm_queue_pair_ee_context_entry_st,
+ log_rq_stride);
+ INS_FLD(log_sq_size, tmp, arbelprm_queue_pair_ee_context_entry_st,
+ log_sq_size);
+ INS_FLD(log_sq_stride, tmp, arbelprm_queue_pair_ee_context_entry_st,
+ log_sq_stride);
+ INS_FLD(dev_ib_data.uar_idx, tmp,
+ arbelprm_queue_pair_ee_context_entry_st, usr_page);
+ INS_FLD(GLOBAL_PD, tmp, arbelprm_queue_pair_ee_context_entry_st, pd);
+ INS_FLD(dev_ib_data.mkey, tmp, arbelprm_queue_pair_ee_context_entry_st,
+ wqe_lkey);
+ INS_FLD(1, tmp, arbelprm_queue_pair_ee_context_entry_st, ssc);
+ INS_FLD(snd_cqn, tmp, arbelprm_queue_pair_ee_context_entry_st, cqn_snd);
+ shift =
+ 32 - MT_BIT_SIZE(arbelprm_queue_pair_ee_context_entry_st,
+ snd_wqe_base_adr_l);
+ INS_FLD(snd_wqe_base_adr_l >> shift, tmp,
+ arbelprm_queue_pair_ee_context_entry_st, snd_wqe_base_adr_l);
+ INS_FLD(snd_db_record_index, tmp,
+ arbelprm_queue_pair_ee_context_entry_st, snd_db_record_index);
+ INS_FLD(1, tmp, arbelprm_queue_pair_ee_context_entry_st, rsc);
+ INS_FLD(rcv_cqn, tmp, arbelprm_queue_pair_ee_context_entry_st, cqn_rcv);
+ shift =
+ 32 - MT_BIT_SIZE(arbelprm_queue_pair_ee_context_entry_st,
+ rcv_wqe_base_adr_l);
+ INS_FLD(rcv_wqe_base_adr_l >> shift, tmp,
+ arbelprm_queue_pair_ee_context_entry_st, rcv_wqe_base_adr_l);
+ INS_FLD(rcv_db_record_index, tmp,
+ arbelprm_queue_pair_ee_context_entry_st, rcv_db_record_index);
+ INS_FLD(qkey, tmp, arbelprm_queue_pair_ee_context_entry_st, q_key);
+
+ tmp =
+ (__u8 *) (&prm->ctx) +
+ MT_BYTE_OFFSET(arbelprm_queue_pair_ee_context_entry_st,
+ primary_address_path);
+ INS_FLD(dev_ib_data.port, tmp, arbelprm_address_path_st, port_number);
+
+}
+
+static void prep_init2rtr_qpee_buf(void *buf)
+{
+ struct qp_ee_state_tarnisition_st *prm;
+
+ prm = (struct qp_ee_state_tarnisition_st *)buf;
+
+ memset(prm, 0, sizeof *prm);
+
+ INS_FLD(MTU_2048, &prm->ctx, arbelprm_queue_pair_ee_context_entry_st,
+ mtu);
+ INS_FLD(11, &prm->ctx, arbelprm_queue_pair_ee_context_entry_st,
+ msg_max);
+}
+
+static void init_av_array(void)
+{
+}
+
+/*
+ * my_log2()
+ */
+static int my_log2(unsigned long arg)
+{
+ int i;
+ __u32 tmp;
+
+ if (arg == 0) {
+ return INT_MIN; /* log2(0) = -infinity */
+ }
+
+ tmp = 1;
+ i = 0;
+ while (tmp < arg) {
+ tmp = tmp << 1;
+ ++i;
+ }
+
+ return i;
+}
+
+/*
+ * get_req_icm_pages
+ */
+static unsigned long get_req_icm_pages(unsigned long log2_reserved,
+ unsigned long app_rsrc,
+ unsigned long entry_size,
+ unsigned long *log2_entries_p)
+{
+ unsigned long size;
+ unsigned long log2_entries;
+
+ log2_entries = my_log2((1 << log2_reserved) + app_rsrc);
+ *log2_entries_p = log2_entries;
+ size = (1 << log2_entries) * entry_size;
+
+ return (size + 4095) >> 12;
+}
+
+static void init_uar_context(void *uar_context_va)
+{
+ void *ptr;
+ /* clear all uar context */
+ memset(uar_context_va, 0, 4096);
+
+ ptr = uar_context_va + MADS_RCV_CQ_ARM_DB_IDX * 8;
+ INS_FLD_TO_BE(UAR_RES_CQ_ARM, ptr, arbelprm_cq_arm_db_record_st, res);
+ INS_FLD_TO_BE(dev_ib_data.mads_qp.rcv_cq.cqn, ptr,
+ arbelprm_cq_arm_db_record_st, cq_number);
+
+ ptr = uar_context_va + MADS_SND_CQ_ARM_DB_IDX * 8;
+ INS_FLD_TO_BE(UAR_RES_CQ_ARM, ptr, arbelprm_cq_arm_db_record_st, res);
+ INS_FLD_TO_BE(dev_ib_data.mads_qp.snd_cq.cqn, ptr,
+ arbelprm_cq_arm_db_record_st, cq_number);
+
+ ptr = uar_context_va + IPOIB_RCV_CQ_ARM_DB_IDX * 8;
+ INS_FLD_TO_BE(UAR_RES_CQ_ARM, ptr, arbelprm_cq_arm_db_record_st, res);
+ INS_FLD_TO_BE(dev_ib_data.ipoib_qp.rcv_cq.cqn, ptr,
+ arbelprm_cq_arm_db_record_st, cq_number);
+
+ ptr = uar_context_va + IPOIB_SND_CQ_ARM_DB_IDX * 8;
+ INS_FLD_TO_BE(UAR_RES_CQ_ARM, ptr, arbelprm_cq_arm_db_record_st, res);
+ INS_FLD_TO_BE(dev_ib_data.ipoib_qp.snd_cq.cqn, ptr,
+ arbelprm_cq_arm_db_record_st, cq_number);
+
+ ptr = uar_context_va + MADS_SND_QP_DB_IDX * 8;
+ INS_FLD_TO_BE(UAR_RES_SQ_DBELL, ptr, arbelprm_qp_db_record_st, res);
+ INS_FLD_TO_BE(dev_ib_data.mads_qp.qpn, ptr, arbelprm_qp_db_record_st,
+ qp_number);
+
+ ptr = uar_context_va + IPOIB_SND_QP_DB_IDX * 8;
+ INS_FLD_TO_BE(UAR_RES_SQ_DBELL, ptr, arbelprm_qp_db_record_st, res);
+ INS_FLD_TO_BE(dev_ib_data.ipoib_qp.qpn, ptr, arbelprm_qp_db_record_st,
+ qp_number);
+
+ ptr = uar_context_va + GROUP_SEP_IDX * 8;
+ INS_FLD_TO_BE(UAR_RES_GROUP_SEP, ptr, arbelprm_cq_arm_db_record_st,
+ res);
+
+ ptr = uar_context_va + MADS_RCV_QP_DB_IDX * 8;
+ INS_FLD_TO_BE(UAR_RES_RQ_DBELL, ptr, arbelprm_qp_db_record_st, res);
+ INS_FLD_TO_BE(dev_ib_data.mads_qp.qpn, ptr, arbelprm_qp_db_record_st,
+ qp_number);
+
+ ptr = uar_context_va + IPOIB_RCV_QP_DB_IDX * 8;
+ INS_FLD_TO_BE(UAR_RES_RQ_DBELL, ptr, arbelprm_qp_db_record_st, res);
+ INS_FLD_TO_BE(dev_ib_data.ipoib_qp.qpn, ptr, arbelprm_qp_db_record_st,
+ qp_number);
+
+ ptr = uar_context_va + MADS_RCV_CQ_CI_DB_IDX * 8;
+ INS_FLD_TO_BE(UAR_RES_CQ_SET_CI, ptr, arbelprm_cq_ci_db_record_st, res);
+ INS_FLD_TO_BE(dev_ib_data.mads_qp.rcv_cq.cqn, ptr,
+ arbelprm_cq_ci_db_record_st, cq_number);
+
+ ptr = uar_context_va + MADS_SND_CQ_CI_DB_IDX * 8;
+ INS_FLD_TO_BE(UAR_RES_CQ_SET_CI, ptr, arbelprm_cq_ci_db_record_st, res);
+ INS_FLD_TO_BE(dev_ib_data.mads_qp.snd_cq.cqn, ptr,
+ arbelprm_cq_ci_db_record_st, cq_number);
+
+ ptr = uar_context_va + IPOIB_RCV_CQ_CI_DB_IDX * 8;
+ INS_FLD_TO_BE(UAR_RES_CQ_SET_CI, ptr, arbelprm_cq_ci_db_record_st, res);
+ INS_FLD_TO_BE(dev_ib_data.ipoib_qp.rcv_cq.cqn, ptr,
+ arbelprm_cq_ci_db_record_st, cq_number);
+
+ ptr = uar_context_va + IPOIB_SND_CQ_CI_DB_IDX * 8;
+ INS_FLD_TO_BE(UAR_RES_CQ_SET_CI, ptr, arbelprm_cq_ci_db_record_st, res);
+ INS_FLD_TO_BE(dev_ib_data.ipoib_qp.snd_cq.cqn, ptr,
+ arbelprm_cq_ci_db_record_st, cq_number);
+
+}
+
+static int setup_hca(__u8 port, void **eq_p)
+{
+ int ret;
+ int rc;
+ struct query_fw_st qfw;
+ struct map_icm_st map_obj;
+ struct dev_lim_st dev_lim;
+ struct init_hca_st init_hca;
+ __u8 log2_pages;
+ unsigned long icm_start, icm_size, tmp;
+ unsigned long log2_entries;
+ __u32 aux_pages;
+ __u32 mem_key, key, tmp_key;
+ __u8 eqn;
+ __u32 event_mask;
+ struct eqe_t *eq_buf;
+ void *inprm;
+ unsigned long bus_addr;
+ struct query_adapter_st qa;
+ __u8 log_max_uars = 1;
+ void *uar_context_va;
+ __u32 uar_context_pa;
+
+ tprintf("called");
+ init_dev_data();
+ inprm = get_inprm_buf();
+
+ rc = reset_hca();
+ if (rc) {
+ eprintf("");
+ return rc;
+ } else {
+ tprintf("reset_hca() success");
+ }
+
+ mdelay(1000); /* wait for 1 sec */
+
+ rc = restore_config();
+ if (rc) {
+ eprintf("");
+ return rc;
+ } else {
+ tprintf("restore_config() success");
+ }
+
+ dev_ib_data.pd = GLOBAL_PD;
+ dev_ib_data.port = port;
+ dev_ib_data.qkey = GLOBAL_QKEY;
+
+ rc = cmd_query_fw(&qfw);
+ if (rc) {
+ eprintf("");
+ return rc;
+ }
+ else {
+ tprintf("cmd_query_fw() success");
+
+ if (print_info) {
+ printf("FW ver = %d.%d.%d\n",
+ qfw.fw_rev_major,
+ qfw.fw_rev_minor,
+ qfw.fw_rev_subminor);
+ }
+
+ tprintf("fw_rev_major=%d", qfw.fw_rev_major);
+ tprintf("fw_rev_minor=%d", qfw.fw_rev_minor);
+ tprintf("fw_rev_subminor=%d", qfw.fw_rev_subminor);
+ tprintf("error_buf_start_h=0x%x", qfw.error_buf_start_h);
+ tprintf("error_buf_start_l=0x%x", qfw.error_buf_start_l);
+ tprintf("error_buf_size=%d", qfw.error_buf_size);
+ }
+
+
+
+ bus_addr =
+ ((unsigned long)((u64) qfw.error_buf_start_h << 32) | qfw.
+ error_buf_start_l);
+ dev_ib_data.error_buf_addr= ioremap(bus_addr,
+ qfw.error_buf_size*4);
+ dev_ib_data.error_buf_size= qfw.error_buf_size;
+ if (!dev_ib_data.error_buf_addr) {
+ eprintf("");
+ return -1;
+ }
+
+
+ bus_addr =
+ ((unsigned long)((u64) qfw.clear_int_addr.addr_h << 32) | qfw.
+ clear_int_addr.addr_l);
+ dev_ib_data.clr_int_addr = bus_to_virt(bus_addr);
+
+ rc = cmd_enable_lam();
+ if (rc == 0x22 /* LAM_NOT_PRE -- need to put a name here */ ) {
+ // ??????
+ } else if (rc == 0) {
+ // ??????
+ } else {
+ eprintf("");
+ return rc;
+ }
+
+ log2_pages = my_log2(qfw.fw_pages);
+
+ memset(&map_obj, 0, sizeof map_obj);
+ map_obj.num_vpm = 1;
+ map_obj.vpm_arr[0].log2_size = log2_pages;
+ map_obj.vpm_arr[0].pa_l = phys_mem.base + phys_mem.offset;
+ rc = cmd_map_fa(&map_obj);
+ if (rc) {
+ eprintf("");
+ return rc;
+ }
+ phys_mem.offset += 1 << (log2_pages + 12);
+
+ rc = cmd_run_fw();
+ if (rc) {
+ ret = -1;
+ eprintf("");
+ goto undo_map_fa;
+ }
+
+ rc = cmd_mod_stat_cfg();
+ if (rc) {
+ ret = -1;
+ eprintf("");
+ goto undo_map_fa;
+ }
+
+ rc = cmd_query_dev_lim(&dev_lim);
+ if (rc) {
+ ret = -1;
+ eprintf("");
+ goto undo_map_fa;
+ }
+
+ dev_ib_data.uar_idx = dev_lim.num_rsvd_uars;
+
+ tprintf("max_icm_size_h=0x%lx", dev_lim.max_icm_size_h);
+ tprintf("max_icm_size_l=0x%lx", dev_lim.max_icm_size_l);
+
+ memset(&init_hca, 0, sizeof init_hca);
+ icm_start = 0;
+ icm_size = 0;
+
+ icm_start += ((dev_lim.num_rsvd_uars + 1) << 12);
+ icm_size += ((dev_lim.num_rsvd_uars + 1) << 12);
+
+ tmp = get_req_icm_pages(dev_lim.log2_rsvd_qps,
+ MAX_APP_QPS,
+ dev_lim.qpc_entry_sz, &log2_entries);
+ init_hca.qpc_base_addr_l = icm_start;
+ init_hca.log_num_of_qp = log2_entries;
+ icm_start += (tmp << 12);
+ icm_size += (tmp << 12);
+
+ init_hca.eqpc_base_addr_l = icm_start;
+ icm_start += (tmp << 12);
+ icm_size += (tmp << 12);
+
+ tmp = get_req_icm_pages(dev_lim.log2_rsvd_srqs,
+ 0, dev_lim.srq_entry_sz, &log2_entries);
+ init_hca.srqc_base_addr_l = icm_start;
+ init_hca.log_num_of_srq = log2_entries;
+ icm_start += (tmp << 12);
+ icm_size += (tmp << 12);
+
+ tmp = get_req_icm_pages(dev_lim.log2_rsvd_ees,
+ 0, dev_lim.eec_entry_sz, &log2_entries);
+ init_hca.eec_base_addr_l = icm_start;
+ init_hca.log_num_of_ee = log2_entries;
+ icm_start += (tmp << 12);
+ icm_size += (tmp << 12);
+
+ init_hca.eeec_base_addr_l = icm_start;
+ icm_start += (tmp << 12);
+ icm_size += (tmp << 12);
+
+ tmp = get_req_icm_pages(dev_lim.log2_rsvd_cqs,
+ MAX_APP_CQS,
+ dev_lim.cqc_entry_sz, &log2_entries);
+ init_hca.cqc_base_addr_l = icm_start;
+ init_hca.log_num_of_cq = log2_entries;
+ icm_start += (tmp << 12);
+ icm_size += (tmp << 12);
+
+ tmp = get_req_icm_pages(dev_lim.log2_rsvd_mtts,
+ 0, dev_lim.mtt_entry_sz, &log2_entries);
+ init_hca.mtt_base_addr_l = icm_start;
+ icm_start += (tmp << 12);
+ icm_size += (tmp << 12);
+
+ tmp = get_req_icm_pages(dev_lim.log2_rsvd_mrws,
+ 1, dev_lim.mpt_entry_sz, &log2_entries);
+ init_hca.mpt_base_addr_l = icm_start;
+ init_hca.log_mpt_sz = log2_entries;
+ icm_start += (tmp << 12);
+ icm_size += (tmp << 12);
+
+ tmp = get_req_icm_pages(dev_lim.log2_rsvd_rdbs, 1, 32, /* size of rdb entry */
+ &log2_entries);
+ init_hca.rdb_base_addr_l = icm_start;
+ icm_start += (tmp << 12);
+ icm_size += (tmp << 12);
+
+ init_hca.eqc_base_addr_l = icm_start;
+ init_hca.log_num_of_eq = LOG2_EQS;
+ tmp = dev_lim.eqc_entry_sz * (1 << LOG2_EQS);
+ icm_start += tmp;
+ icm_size += tmp;
+
+ init_hca.mc_base_addr_l = icm_start;
+ init_hca.log_mc_table_entry_sz =
+ my_log2(MT_STRUCT_SIZE(arbelprm_mgm_entry_st));
+ init_hca.mc_table_hash_sz = 8;
+ init_hca.log_mc_table_sz = 3;
+ icm_size +=
+ (MT_STRUCT_SIZE(arbelprm_mgm_entry_st) * init_hca.mc_table_hash_sz);
+ icm_start +=
+ (MT_STRUCT_SIZE(arbelprm_mgm_entry_st) * init_hca.mc_table_hash_sz);
+
+ rc = cmd_set_icm_size(icm_size, &aux_pages);
+ if (rc) {
+ ret = -1;
+ eprintf("");
+ goto undo_map_fa;
+ }
+
+ memset(&map_obj, 0, sizeof map_obj);
+ map_obj.num_vpm = 1;
+ map_obj.vpm_arr[0].pa_l = phys_mem.base + phys_mem.offset;
+ map_obj.vpm_arr[0].log2_size = my_log2(aux_pages);
+ rc = cmd_map_icm_aux(&map_obj);
+ if (rc) {
+ ret = -1;
+ eprintf("");
+ goto undo_map_fa;
+ }
+ phys_mem.offset += (1 << (map_obj.vpm_arr[0].log2_size + 12));
+
+ uar_context_pa = phys_mem.base + phys_mem.offset +
+ dev_ib_data.uar_idx * 4096;
+ uar_context_va = phys_to_virt(uar_context_pa);
+ tprintf("uar_context: va=0x%lx, pa=0x%lx", uar_context_va,
+ uar_context_pa);
+ dev_ib_data.uar_context_base = uar_context_va;
+
+ memset(&map_obj, 0, sizeof map_obj);
+ map_obj.num_vpm = 1;
+ map_obj.vpm_arr[0].pa_l = phys_mem.base + phys_mem.offset;
+ map_obj.vpm_arr[0].log2_size = my_log2((icm_size + 4095) >> 12);
+ rc = cmd_map_icm(&map_obj);
+ if (rc) {
+ ret = -1;
+ eprintf("");
+ goto undo_map_fa;
+ }
+ phys_mem.offset += (1 << (map_obj.vpm_arr[0].log2_size + 12));
+
+ init_hca.log_max_uars = log_max_uars;
+ tprintf("inprm: va=0x%lx, pa=0x%lx", inprm, virt_to_bus(inprm));
+ prep_init_hca_buf(&init_hca, inprm);
+ rc = cmd_init_hca(inprm, MT_STRUCT_SIZE(arbelprm_init_hca_st));
+ if (rc) {
+ ret = -1;
+ eprintf("");
+ goto undo_map_fa;
+ }
+
+ rc = cmd_query_adapter(&qa);
+ if (rc) {
+ eprintf("");
+ return rc;
+ }
+ dev_ib_data.clr_int_data = 1 << qa.intapin;
+
+ tmp_key = 1 << dev_lim.log2_rsvd_mrws | MKEY_PREFIX;
+ mem_key = 1 << (dev_lim.log2_rsvd_mrws + 8) | (MKEY_PREFIX >> 24);
+ prep_sw2hw_mpt_buf(inprm, tmp_key);
+ rc = cmd_sw2hw_mpt(&key, 1 << dev_lim.log2_rsvd_mrws, inprm,
+ SW2HW_MPT_IBUF_SZ);
+ if (rc) {
+ ret = -1;
+ eprintf("");
+ goto undo_map_fa;
+ } else {
+ tprintf("cmd_sw2hw_mpt() success, key=0x%lx", mem_key);
+ }
+ dev_ib_data.mkey = mem_key;
+
+ eqn = EQN;
+ /* allocate a single EQ which will receive
+ all the events */
+ eq_buf = dev_buffers_p->eq_buf;
+ init_eq_buf(eq_buf); /* put in HW ownership */
+ prep_sw2hw_eq_buf(inprm, eq_buf);
+ rc = cmd_sw2hw_eq(SW2HW_EQ_IBUF_SZ);
+ if (rc) {
+ ret = -1;
+ eprintf("");
+ goto undo_sw2hw_mpt;
+ } else
+ tprintf("cmd_sw2hw_eq() success");
+
+ event_mask = (1 << XDEV_EV_TYPE_CQ_COMP) |
+ (1 << XDEV_EV_TYPE_CQ_ERR) |
+ (1 << XDEV_EV_TYPE_LOCAL_WQ_CATAS_ERR) |
+ (1 << XDEV_EV_TYPE_PORT_ERR) |
+ (1 << XDEV_EV_TYPE_LOCAL_WQ_INVALID_REQ_ERR) |
+ (1 << XDEV_EV_TYPE_LOCAL_WQ_ACCESS_VIOL_ERR) |
+ (1 << TAVOR_IF_EV_TYPE_OVERRUN);
+ rc = cmd_map_eq(eqn, event_mask, 1);
+ if (rc) {
+ ret = -1;
+ eprintf("");
+ goto undo_sw2hw_eq;
+ } else
+ tprintf("cmd_map_eq() success");
+
+ dev_ib_data.eq.eqn = eqn;
+ dev_ib_data.eq.eq_buf = eq_buf;
+ dev_ib_data.eq.cons_counter = 0;
+ dev_ib_data.eq.eq_size = 1 << LOG2_EQ_SZ;
+ bus_addr =
+ ((unsigned long)((u64) qfw.eq_ci_table.addr_h << 32) | qfw.
+ eq_ci_table.addr_l)
+ + eqn * 8;
+ dev_ib_data.eq.ci_base_base_addr = bus_to_virt(bus_addr);
+ *eq_p = &dev_ib_data.eq;
+
+ prep_init_ib_buf(inprm);
+ rc = cmd_init_ib(port, inprm, INIT_IB_IBUF_SZ);
+ if (rc) {
+ ret = -1;
+ eprintf("");
+ goto undo_sw2hw_eq;
+ } else
+ tprintf("cmd_init_ib() success");
+
+ init_av_array();
+ tprintf("init_av_array() done");
+
+ /* set the qp and cq numbers according
+ to the results of query_dev_lim */
+ dev_ib_data.mads_qp.qpn = (1 << dev_lim.log2_rsvd_qps) +
+ +QPN_BASE + MADS_QPN_SN;
+ dev_ib_data.ipoib_qp.qpn = (1 << dev_lim.log2_rsvd_qps) +
+ +QPN_BASE + IPOIB_QPN_SN;
+
+ dev_ib_data.mads_qp.snd_cq.cqn = (1 << dev_lim.log2_rsvd_cqs) +
+ MADS_SND_CQN_SN;
+ dev_ib_data.mads_qp.rcv_cq.cqn = (1 << dev_lim.log2_rsvd_cqs) +
+ MADS_RCV_CQN_SN;
+
+ dev_ib_data.ipoib_qp.snd_cq.cqn = (1 << dev_lim.log2_rsvd_cqs) +
+ IPOIB_SND_CQN_SN;
+ dev_ib_data.ipoib_qp.rcv_cq.cqn = (1 << dev_lim.log2_rsvd_cqs) +
+ IPOIB_RCV_CQN_SN;
+
+ init_uar_context(uar_context_va);
+
+ ret = 0;
+ goto exit;
+
+ undo_sw2hw_eq:
+ rc = cmd_hw2sw_eq(eqn);
+ if (rc)
+ eprintf("");
+ else
+ tprintf("cmd_hw2sw_eq() success");
+
+ undo_sw2hw_mpt:
+ rc = cmd_hw2sw_mpt(tmp_key);
+ if (rc)
+ eprintf("");
+
+ undo_map_fa:
+ rc = cmd_unmap_fa();
+ if (rc)
+ eprintf("");
+
+ exit:
+ return ret;
+}
+
+static void *get_inprm_buf(void)
+{
+ return dev_buffers_p->inprm_buf;
+}
+
+static void *get_outprm_buf(void)
+{
+ return dev_buffers_p->outprm_buf;
+}
+
+static void *get_send_wqe_buf(void *wqe, __u8 index)
+{
+ struct ud_send_wqe_st *snd_wqe = wqe;
+
+ return bus_to_virt(be32_to_cpu(snd_wqe->mpointer[index].local_addr_l));
+}
+
+static void *get_rcv_wqe_buf(void *wqe, __u8 index)
+{
+ struct recv_wqe_st *rcv_wqe = wqe;
+
+ return bus_to_virt(be32_to_cpu(rcv_wqe->mpointer[index].local_addr_l));
+}
+
+static void modify_av_params(struct ud_av_st *av,
+ __u16 dlid,
+ __u8 g,
+ __u8 sl, __u8 rate, union ib_gid_u *gid, __u32 qpn)
+{
+ memset(&av->av, 0, sizeof av->av);
+
+ INS_FLD_TO_BE(dev_ib_data.port, &av->av, arbelprm_ud_address_vector_st,
+ port_number);
+ INS_FLD_TO_BE(dev_ib_data.pd, &av->av, arbelprm_ud_address_vector_st,
+ pd);
+ INS_FLD_TO_BE(dlid, &av->av, arbelprm_ud_address_vector_st, rlid);
+ INS_FLD_TO_BE(g, &av->av, arbelprm_ud_address_vector_st, g);
+ INS_FLD_TO_BE(sl, &av->av, arbelprm_ud_address_vector_st, sl);
+ INS_FLD_TO_BE(3, &av->av, arbelprm_ud_address_vector_st, msg);
+
+ if (rate >= 3)
+ INS_FLD_TO_BE(0, &av->av, arbelprm_ud_address_vector_st, max_stat_rate); /* 4x */
+ else
+ INS_FLD_TO_BE(1, &av->av, arbelprm_ud_address_vector_st, max_stat_rate); /* 1x */
+
+ if (g) {
+ if (gid) {
+ INS_FLD(*((__u32 *) (&gid->raw[0])), &av->av,
+ arbelprm_ud_address_vector_st, rgid_127_96);
+ INS_FLD(*((__u32 *) (&gid->raw[4])), &av->av,
+ arbelprm_ud_address_vector_st, rgid_95_64);
+ INS_FLD(*((__u32 *) (&gid->raw[8])), &av->av,
+ arbelprm_ud_address_vector_st, rgid_63_32);
+ INS_FLD(*((__u32 *) (&gid->raw[12])), &av->av,
+ arbelprm_ud_address_vector_st, rgid_31_0);
+ } else {
+ INS_FLD(0, &av->av, arbelprm_ud_address_vector_st,
+ rgid_127_96);
+ INS_FLD(0, &av->av, arbelprm_ud_address_vector_st,
+ rgid_95_64);
+ INS_FLD(0, &av->av, arbelprm_ud_address_vector_st,
+ rgid_63_32);
+ INS_FLD(0, &av->av, arbelprm_ud_address_vector_st,
+ rgid_31_0);
+ }
+ } else {
+ INS_FLD(0, &av->av, arbelprm_ud_address_vector_st, rgid_127_96);
+ INS_FLD(0, &av->av, arbelprm_ud_address_vector_st, rgid_95_64);
+ INS_FLD(0, &av->av, arbelprm_ud_address_vector_st, rgid_63_32);
+ INS_FLD(2, &av->av, arbelprm_ud_address_vector_st, rgid_31_0);
+ }
+ av->dest_qp = qpn;
+ av->qkey = dev_ib_data.qkey;
+}
+
+static void init_cq_buf(union cqe_st *cq_buf, __u8 num_cqes)
+{
+ int i;
+
+ memset(cq_buf, 0, sizeof(union cqe_st) * num_cqes);
+ for (i = 0; i < num_cqes; ++i) {
+ WRITE_BYTE_VOL(&cq_buf[i], CQE_OWNER_OFFSET, CQE_OWNER_VAL_HW);
+ }
+}
+
+static int post_rcv_buf(struct udqp_st *qp, struct recv_wqe_st *rcv_wqe)
+{
+ int i;
+
+ /* put a valid lkey */
+ for (i = 0; i < MAX_SCATTER; ++i) {
+ rcv_wqe->mpointer[i].lkey = cpu_to_be32(dev_ib_data.mkey);
+ }
+
+ qp->post_rcv_counter++;
+ WRITE_WORD_VOL(qp->rcv_uar_context, 2, htons(qp->post_rcv_counter));
+
+ return 0;
+}
+
+static int post_send_req(void *qph, void *wqeh, __u8 num_gather)
+{
+ int rc;
+ struct udqp_st *qp = qph;
+ struct ud_send_wqe_st *snd_wqe = wqeh;
+ struct send_doorbell_st dbell;
+ __u32 nds;
+
+ qp->post_send_counter++;
+
+ WRITE_WORD_VOL(qp->send_uar_context, 2, htons(qp->post_send_counter));
+
+ memset(&dbell, 0, sizeof dbell);
+ INS_FLD(XDEV_NOPCODE_SEND, &dbell, arbelprm_send_doorbell_st, nopcode);
+ INS_FLD(1, &dbell, arbelprm_send_doorbell_st, f);
+ INS_FLD(qp->post_send_counter - 1, &dbell, arbelprm_send_doorbell_st,
+ wqe_counter);
+ INS_FLD(1, &dbell, arbelprm_send_doorbell_st, wqe_cnt);
+ nds = (sizeof(snd_wqe->next) +
+ sizeof(snd_wqe->udseg) +
+ sizeof(snd_wqe->mpointer[0]) * num_gather) >> 4;
+ INS_FLD(nds, &dbell, arbelprm_send_doorbell_st, nds);
+ INS_FLD(qp->qpn, &dbell, arbelprm_send_doorbell_st, qpn);
+
+ if (qp->last_posted_snd_wqe) {
+ INS_FLD_TO_BE(nds,
+ &qp->last_posted_snd_wqe->next.next,
+ arbelprm_wqe_segment_next_st, nds);
+ INS_FLD_TO_BE(1,
+ &qp->last_posted_snd_wqe->next.next,
+ arbelprm_wqe_segment_next_st, f);
+ INS_FLD_TO_BE(XDEV_NOPCODE_SEND,
+ &qp->last_posted_snd_wqe->next.next,
+ arbelprm_wqe_segment_next_st, nopcode);
+ }
+
+ rc = cmd_post_doorbell(&dbell, POST_SND_OFFSET);
+ if (!rc) {
+ qp->last_posted_snd_wqe = snd_wqe;
+ }
+
+ return rc;
+
+}
+
+static int create_mads_qp(void **qp_pp, void **snd_cq_pp, void **rcv_cq_pp)
+{
+ __u8 i, next_i, j, k;
+ int rc;
+ struct udqp_st *qp;
+ __u32 bus_addr;
+ __u8 nds;
+ void *ptr;
+
+ qp = &dev_ib_data.mads_qp;
+
+ /* set the pointer to the receive WQEs buffer */
+ qp->rcv_wq = dev_buffers_p->mads_qp_rcv_queue;
+
+ qp->send_buf_sz = MAD_BUF_SZ;
+ qp->rcv_buf_sz = MAD_BUF_SZ;
+
+ qp->max_recv_wqes = NUM_MADS_RCV_WQES; /* max wqes in this work queue */
+ qp->recv_wqe_cur_free = NUM_MADS_RCV_WQES; /* current free wqes */
+ qp->recv_wqe_alloc_idx = 0; /* index from wqes can be allocated if there are free wqes */
+
+ qp->rcv_uar_context =
+ dev_ib_data.uar_context_base + 8 * MADS_RCV_QP_DB_IDX;
+ qp->send_uar_context =
+ dev_ib_data.uar_context_base + 8 * MADS_SND_QP_DB_IDX;
+
+ memset(&qp->rcv_wq[0], 0, NUM_MADS_RCV_WQES * sizeof(qp->rcv_wq[0]));
+ nds = sizeof(qp->rcv_wq[0].wqe) >> 4;
+ /* iterrate through the list */
+ for (j = 0, i = 0, next_i = 1;
+ j < NUM_MADS_RCV_WQES;
+ MOD_INC(i, NUM_MADS_RCV_WQES), MOD_INC(next_i, NUM_MADS_RCV_WQES),
+ ++j) {
+
+ qp->rcv_bufs[i] = ib_buffers.rcv_mad_buf[i];
+ /* link the WQE to the next one */
+ bus_addr = virt_to_bus(&qp->rcv_wq[next_i].wqe);
+ ptr = qp->rcv_wq[i].wqe.control +
+ MT_BYTE_OFFSET(arbelprm_wqe_segment_ctrl_recv_st,
+ wqe_segment_next);
+ INS_FLD(bus_addr >> 6, ptr, arbelprm_recv_wqe_segment_next_st,
+ nda_31_6);
+ INS_FLD(nds, ptr, arbelprm_recv_wqe_segment_next_st, nds);
+
+ /* set the allocated buffers */
+ qp->rcv_bufs[i] = ib_buffers.rcv_mad_buf[i];
+ bus_addr = virt_to_bus(qp->rcv_bufs[i]);
+ qp->rcv_wq[i].wqe.mpointer[0].local_addr_l = bus_addr;
+ qp->rcv_wq[i].wqe.mpointer[0].byte_count = GRH_SIZE;
+ bus_addr = virt_to_bus(qp->rcv_bufs[i] + GRH_SIZE);
+ qp->rcv_wq[i].wqe.mpointer[1].local_addr_l = bus_addr;
+ qp->rcv_wq[i].wqe.mpointer[1].byte_count = MAD_BUF_SZ;
+
+ for (k = 0; k < (((sizeof(qp->rcv_wq[i])) >> 4) - 1); ++k) {
+ qp->rcv_wq[i].wqe.mpointer[k].lkey = INVALID_WQE_LKEY;
+ }
+ }
+ cpu_to_be_buf(&qp->rcv_wq[0],
+ NUM_MADS_RCV_WQES * sizeof(qp->rcv_wq[0]));
+
+ for (i = 0; i < qp->max_recv_wqes; ++i) {
+ qp->rcv_wq[i].wqe_cont.qp = qp;
+ }
+
+ /* set the pointer to the send WQEs buffer */
+ qp->snd_wq = dev_buffers_p->mads_qp_snd_queue;
+
+ qp->snd_wqe_alloc_idx = 0;
+ qp->max_snd_wqes = NUM_MADS_SND_WQES;
+ qp->snd_wqe_cur_free = NUM_MADS_SND_WQES;
+
+ memset(&qp->snd_wq[0], 0, NUM_MADS_SND_WQES * sizeof(qp->snd_wq[i]));
+ /* iterrate through the list */
+ for (j = 0, i = 0, next_i = 1;
+ j < NUM_MADS_RCV_WQES;
+ MOD_INC(i, NUM_MADS_SND_WQES), MOD_INC(next_i, NUM_MADS_SND_WQES),
+ ++j) {
+
+ /* link the WQE to the next one */
+ bus_addr = virt_to_bus(&qp->snd_wq[next_i].wqe_cont.wqe);
+ INS_FLD(bus_addr >> 6, &qp->snd_wq[i].wqe_cont.wqe.next.next,
+ arbelprm_wqe_segment_next_st, nda_31_6);
+
+ /* set the allocated buffers */
+ qp->snd_bufs[i] = ib_buffers.send_mad_buf[i];
+ bus_addr = virt_to_bus(qp->snd_bufs[i]);
+ qp->snd_wq[i].wqe_cont.wqe.mpointer[0].local_addr_l = bus_addr;
+ qp->snd_wq[i].wqe_cont.wqe.mpointer[0].lkey = dev_ib_data.mkey;
+ qp->snd_wq[i].wqe_cont.wqe.mpointer[0].byte_count =
+ qp->send_buf_sz;
+
+ }
+
+ cpu_to_be_buf(&qp->snd_wq[0],
+ NUM_MADS_SND_WQES * sizeof(qp->snd_wq[i]));
+
+ for (i = 0; i < qp->max_snd_wqes; ++i) {
+ qp->snd_wq[i].wqe_cont.qp = qp;
+ }
+
+ /* qp number and cq numbers are already set up */
+ qp->snd_cq.cq_buf = dev_buffers_p->mads_snd_cq_buf;
+ qp->rcv_cq.cq_buf = dev_buffers_p->mads_rcv_cq_buf;
+ qp->snd_cq.num_cqes = NUM_MADS_SND_CQES;
+ qp->rcv_cq.num_cqes = NUM_MADS_RCV_CQES;
+ qp->snd_cq.arm_db_ctx_idx = MADS_SND_CQ_ARM_DB_IDX;
+ qp->snd_cq.ci_db_ctx_idx = MADS_SND_CQ_CI_DB_IDX;
+ qp->rcv_cq.arm_db_ctx_idx = MADS_RCV_CQ_ARM_DB_IDX;
+ qp->rcv_cq.ci_db_ctx_idx = MADS_RCV_CQ_CI_DB_IDX;
+ qp->rcv_db_record_index = MADS_RCV_QP_DB_IDX;
+ qp->snd_db_record_index = MADS_SND_QP_DB_IDX;
+ qp->qkey = GLOBAL_QKEY;
+ rc = create_udqp(qp);
+ if (!rc) {
+ *qp_pp = qp;
+ *snd_cq_pp = &qp->snd_cq;
+ *rcv_cq_pp = &qp->rcv_cq;
+ }
+
+ return rc;
+}
+
+static int create_ipoib_qp(void **qp_pp,
+ void **snd_cq_pp, void **rcv_cq_pp, __u32 qkey)
+{
+ __u8 i, next_i, j, k;
+ int rc;
+ struct udqp_st *qp;
+ __u32 bus_addr;
+ __u8 nds;
+ void *ptr;
+
+ qp = &dev_ib_data.ipoib_qp;
+
+ /* set the pointer to the receive WQEs buffer */
+ qp->rcv_wq = dev_buffers_p->ipoib_qp_rcv_queue;
+
+ qp->send_buf_sz = IPOIB_SND_BUF_SZ;
+ qp->rcv_buf_sz = IPOIB_RCV_BUF_SZ;
+
+ qp->max_recv_wqes = NUM_IPOIB_RCV_WQES;
+ qp->recv_wqe_cur_free = NUM_IPOIB_RCV_WQES;
+
+ qp->rcv_uar_context =
+ dev_ib_data.uar_context_base + 8 * IPOIB_RCV_QP_DB_IDX;
+ qp->send_uar_context =
+ dev_ib_data.uar_context_base + 8 * IPOIB_SND_QP_DB_IDX;
+
+ memset(&qp->rcv_wq[0], 0, NUM_IPOIB_RCV_WQES * sizeof(qp->rcv_wq[0]));
+ nds = sizeof(qp->rcv_wq[0].wqe) >> 4;
+ /* iterrate through the list */
+ for (j = 0, i = 0, next_i = 1;
+ j < NUM_IPOIB_RCV_WQES;
+ MOD_INC(i, NUM_IPOIB_RCV_WQES), MOD_INC(next_i,
+ NUM_IPOIB_RCV_WQES), ++j) {
+
+ /* link the WQE to the next one */
+ bus_addr = virt_to_bus(&qp->rcv_wq[next_i].wqe);
+ ptr = qp->rcv_wq[i].wqe.control +
+ MT_BYTE_OFFSET(arbelprm_wqe_segment_ctrl_recv_st,
+ wqe_segment_next);
+ INS_FLD(bus_addr >> 6, ptr, arbelprm_recv_wqe_segment_next_st,
+ nda_31_6);
+ INS_FLD(nds, ptr, arbelprm_recv_wqe_segment_next_st, nds);
+
+ /* set the allocated buffers */
+ qp->rcv_bufs[i] = ib_buffers.ipoib_rcv_buf[i];
+ bus_addr = virt_to_bus(qp->rcv_bufs[i]);
+ qp->rcv_wq[i].wqe.mpointer[0].local_addr_l = bus_addr;
+ qp->rcv_wq[i].wqe.mpointer[0].byte_count = GRH_SIZE;
+ bus_addr = virt_to_bus(qp->rcv_bufs[i] + GRH_SIZE);
+ qp->rcv_wq[i].wqe.mpointer[1].local_addr_l = bus_addr;
+ qp->rcv_wq[i].wqe.mpointer[1].byte_count = IPOIB_RCV_BUF_SZ;
+
+ for (k = 0; k < (((sizeof(qp->rcv_wq[i].wqe)) >> 4) - 1); ++k) {
+ qp->rcv_wq[i].wqe.mpointer[k].lkey = INVALID_WQE_LKEY;
+ }
+ }
+ cpu_to_be_buf(&qp->rcv_wq[0],
+ NUM_IPOIB_RCV_WQES * sizeof(qp->rcv_wq[0]));
+
+ for (i = 0; i < qp->max_recv_wqes; ++i) {
+ qp->rcv_wq[i].wqe_cont.qp = qp;
+ }
+
+ /* set the pointer to the send WQEs buffer */
+ qp->snd_wq = dev_buffers_p->ipoib_qp_snd_queue;
+
+ qp->snd_wqe_alloc_idx = 0;
+ qp->max_snd_wqes = NUM_IPOIB_SND_WQES;
+ qp->snd_wqe_cur_free = NUM_IPOIB_SND_WQES;
+
+ memset(&qp->snd_wq[0], 0, NUM_IPOIB_SND_WQES * sizeof(qp->snd_wq[i]));
+ /* iterrate through the list */
+ for (j = 0, i = 0, next_i = 1;
+ j < NUM_IPOIB_RCV_WQES;
+ MOD_INC(i, NUM_IPOIB_SND_WQES), MOD_INC(next_i,
+ NUM_IPOIB_SND_WQES), ++j) {
+
+ /* link the WQE to the next one */
+ bus_addr = virt_to_bus(&qp->snd_wq[next_i].wqe_cont.wqe);
+ INS_FLD(bus_addr >> 6, &qp->snd_wq[i].wqe_cont.wqe.next.next,
+ arbelprm_wqe_segment_next_st, nda_31_6);
+
+ /* set the allocated buffers */
+ qp->snd_bufs[i] = ib_buffers.send_ipoib_buf[i];
+ bus_addr = virt_to_bus(qp->snd_bufs[i]);
+ qp->snd_wq[i].wqe_cont.wqe.mpointer[0].local_addr_l = bus_addr;
+ qp->snd_wq[i].wqe_cont.wqe.mpointer[0].lkey = dev_ib_data.mkey;
+
+ }
+ cpu_to_be_buf(&qp->snd_wq[0],
+ NUM_IPOIB_SND_WQES * sizeof(qp->snd_wq[i]));
+
+ for (i = 0; i < qp->max_snd_wqes; ++i) {
+ qp->snd_wq[i].wqe_cont.qp = qp;
+ }
+
+ /* qp number and cq numbers are already set up */
+ qp->snd_cq.cq_buf = dev_buffers_p->ipoib_snd_cq_buf;
+ qp->rcv_cq.cq_buf = dev_buffers_p->ipoib_rcv_cq_buf;
+ qp->snd_cq.num_cqes = NUM_IPOIB_SND_CQES;
+ qp->rcv_cq.num_cqes = NUM_IPOIB_RCV_CQES;
+ qp->snd_cq.arm_db_ctx_idx = IPOIB_SND_CQ_ARM_DB_IDX;
+ qp->snd_cq.ci_db_ctx_idx = IPOIB_SND_CQ_CI_DB_IDX;
+ qp->rcv_cq.arm_db_ctx_idx = IPOIB_RCV_CQ_ARM_DB_IDX;
+ qp->rcv_cq.ci_db_ctx_idx = IPOIB_RCV_CQ_CI_DB_IDX;
+ qp->rcv_db_record_index = IPOIB_RCV_QP_DB_IDX;
+ qp->snd_db_record_index = IPOIB_SND_QP_DB_IDX;
+ qp->qkey = qkey;
+ rc = create_udqp(qp);
+ if (!rc) {
+ *qp_pp = qp;
+ *snd_cq_pp = &qp->snd_cq;
+ *rcv_cq_pp = &qp->rcv_cq;
+ }
+
+ return rc;
+}
+
+static int create_udqp(struct udqp_st *qp)
+{
+ int rc, ret = 0;
+ void *inprm;
+ struct recv_wqe_st *rcv_wqe;
+
+ inprm = dev_buffers_p->inprm_buf;
+
+ qp->rcv_cq.arm_db_ctx_pointer =
+ dev_ib_data.uar_context_base + 8 * qp->rcv_cq.arm_db_ctx_idx;
+ qp->rcv_cq.ci_db_ctx_pointer =
+ dev_ib_data.uar_context_base + 8 * qp->rcv_cq.ci_db_ctx_idx;
+ qp->snd_cq.arm_db_ctx_pointer =
+ dev_ib_data.uar_context_base + 8 * qp->snd_cq.arm_db_ctx_idx;
+ qp->snd_cq.ci_db_ctx_pointer =
+ dev_ib_data.uar_context_base + 8 * qp->snd_cq.ci_db_ctx_idx;
+
+ /* create send CQ */
+ init_cq_buf(qp->snd_cq.cq_buf, qp->snd_cq.num_cqes);
+ qp->snd_cq.cons_counter = 0;
+ prep_sw2hw_cq_buf(inprm,
+ dev_ib_data.eq.eqn,
+ qp->snd_cq.cqn,
+ qp->snd_cq.cq_buf,
+ qp->snd_cq.ci_db_ctx_idx, qp->snd_cq.arm_db_ctx_idx);
+
+ rc = cmd_sw2hw_cq(qp->snd_cq.cqn, inprm, SW2HW_CQ_IBUF_SZ);
+ if (rc) {
+ ret = -1;
+ eprintf("");
+ goto exit;
+ }
+
+ /* create receive CQ */
+ init_cq_buf(qp->rcv_cq.cq_buf, qp->rcv_cq.num_cqes);
+ qp->rcv_cq.cons_counter = 0;
+ memset(inprm, 0, SW2HW_CQ_IBUF_SZ);
+ prep_sw2hw_cq_buf(inprm,
+ dev_ib_data.eq.eqn,
+ qp->rcv_cq.cqn,
+ qp->rcv_cq.cq_buf,
+ qp->rcv_cq.ci_db_ctx_idx, qp->rcv_cq.arm_db_ctx_idx);
+
+ rc = cmd_sw2hw_cq(qp->rcv_cq.cqn, inprm, SW2HW_CQ_IBUF_SZ);
+ if (rc) {
+ ret = -1;
+ eprintf("");
+ goto undo_snd_cq;
+ }
+
+ prep_rst2init_qpee_buf(inprm,
+ qp->snd_cq.cqn,
+ qp->rcv_cq.cqn,
+ qp->qkey,
+ my_log2(qp->max_recv_wqes),
+ my_log2(sizeof(qp->rcv_wq[0])) - 4,
+ my_log2(qp->max_snd_wqes),
+ my_log2(sizeof(qp->snd_wq[0])) - 4,
+ virt_to_bus(qp->snd_wq),
+ qp->snd_db_record_index,
+ virt_to_bus(qp->rcv_wq),
+ qp->rcv_db_record_index);
+
+ rc = cmd_rst2init_qpee(qp->qpn, inprm, QPCTX_IBUF_SZ);
+ if (rc) {
+ ret = -1;
+ eprintf("");
+ goto undo_rcv_cq;
+ }
+
+ qp->last_posted_rcv_wqe = NULL;
+ qp->last_posted_snd_wqe = NULL;
+
+ /* post all the buffers to the receive queue */
+ while (1) {
+ /* allocate wqe */
+ rcv_wqe = alloc_rcv_wqe(qp);
+ if (!rcv_wqe)
+ break;
+
+ /* post the buffer */
+ rc = post_rcv_buf(qp, rcv_wqe);
+ if (rc) {
+ ret = -1;
+ eprintf("");
+ goto undo_rcv_cq;
+ }
+ }
+
+ prep_init2rtr_qpee_buf(inprm);
+ rc = cmd_init2rtr_qpee(qp->qpn, inprm, QPCTX_IBUF_SZ);
+ if (rc) {
+ ret = -1;
+ eprintf("");
+ goto undo_rcv_cq;
+ }
+
+ memset(inprm, 0, QPCTX_IBUF_SZ);
+ rc = cmd_rtr2rts_qpee(qp->qpn, inprm, QPCTX_IBUF_SZ);
+ if (rc) {
+ ret = -1;
+ eprintf("");
+ goto undo_rcv_cq;
+ }
+
+ goto exit;
+
+ undo_rcv_cq:
+ rc = cmd_hw2sw_cq(qp->rcv_cq.cqn);
+ if (rc)
+ eprintf("");
+
+ undo_snd_cq:
+ rc = cmd_hw2sw_cq(qp->snd_cq.cqn);
+ if (rc)
+ eprintf("");
+
+ exit:
+ return ret;
+}
+
+static int destroy_udqp(struct udqp_st *qp)
+{
+ int rc;
+
+ rc = cmd_2err_qpee(qp->qpn);
+ if (rc) {
+ eprintf("");
+ return rc;
+ }
+ tprintf("cmd_2err_qpee(0x%lx) success", qp->qpn);
+
+ rc = cmd_2rst_qpee(qp->qpn);
+ if (rc) {
+ eprintf("");
+ return rc;
+ }
+ tprintf("cmd_2rst_qpee(0x%lx) success", qp->qpn);
+
+ rc = cmd_hw2sw_cq(qp->rcv_cq.cqn);
+ if (rc) {
+ eprintf("");
+ return rc;
+ }
+ tprintf("cmd_hw2sw_cq(0x%lx) success", qp->snd_cq.cqn);
+
+ rc = cmd_hw2sw_cq(qp->snd_cq.cqn);
+ if (rc) {
+ eprintf("");
+ return rc;
+ }
+ tprintf("cmd_hw2sw_cq(0x%lx) success", qp->rcv_cq.cqn);
+
+ return rc;
+}
+
+static void prep_send_wqe_buf(void *qph,
+ void *avh,
+ void *wqeh,
+ const void *buf,
+ unsigned int offset, __u16 len, __u8 e)
+{
+ struct ud_send_wqe_st *snd_wqe = wqeh;
+ struct ud_av_st *av = avh;
+
+ if (qph) {
+ }
+ /* suppress warnings */
+ INS_FLD_TO_BE(e, &snd_wqe->next.control,
+ arbelprm_wqe_segment_ctrl_send_st, e);
+ INS_FLD_TO_BE(1, &snd_wqe->next.control,
+ arbelprm_wqe_segment_ctrl_send_st, always1);
+ INS_FLD_TO_BE(1, &snd_wqe->next.next, arbelprm_wqe_segment_next_st,
+ always1);
+ memcpy(&snd_wqe->udseg, &av->av, sizeof av->av);
+ INS_FLD_TO_BE(av->dest_qp, snd_wqe->udseg.av,
+ arbelprm_wqe_segment_ud_st, destination_qp);
+ INS_FLD_TO_BE(av->qkey, snd_wqe->udseg.av, arbelprm_wqe_segment_ud_st,
+ q_key);
+
+ if (buf) {
+ memcpy(bus_to_virt
+ (be32_to_cpu(snd_wqe->mpointer[0].local_addr_l)) +
+ offset, buf, len);
+ len += offset;
+ }
+ snd_wqe->mpointer[0].byte_count = cpu_to_be32(len);
+}
+
+static void *alloc_ud_av(void)
+{
+ u8 next_free;
+
+ if (dev_ib_data.udav.udav_next_free == FL_EOL) {
+ return NULL;
+ }
+
+ next_free = dev_ib_data.udav.udav_next_free;
+ dev_ib_data.udav.udav_next_free =
+ dev_buffers_p->av_array[next_free].ud_av.next_free;
+ tprintf("allocated udav %d", next_free);
+ return &dev_buffers_p->av_array[next_free].ud_av;
+}
+
+static void free_ud_av(void *avh)
+{
+ union ud_av_u *avu;
+ __u8 idx, old_idx;
+ struct ud_av_st *av = avh;
+
+ avu = (union ud_av_u *)av;
+
+ idx = avu - dev_buffers_p->av_array;
+ tprintf("freeing udav idx=%d", idx);
+ old_idx = dev_ib_data.udav.udav_next_free;
+ dev_ib_data.udav.udav_next_free = idx;
+ avu->ud_av.next_free = old_idx;
+}
+
+static int update_cq_cons_idx(struct cq_st *cq)
+{
+ /* write doorbell record */
+ WRITE_DWORD_VOL(cq->ci_db_ctx_pointer, 0, htonl(cq->cons_counter));
+
+ /*
+ INS_FLD_TO_BE(cq->cons_counter,
+ cq->ci_db_ctx_pointer,
+ arbelprm_cq_arm_db_record_st,
+ counter);
+
+ INS_FLD_TO_BE(cq->cqn,
+ cq->ci_db_ctx_pointer,
+ arbelprm_cq_arm_db_record_st,
+ cq_number);
+
+ INS_FLD_TO_BE(1,
+ cq->ci_db_ctx_pointer,
+ arbelprm_cq_arm_db_record_st,
+ res); */
+
+ return 0;
+}
+
+static int poll_cq(void *cqh, union cqe_st *cqe_p, u8 * num_cqes)
+{
+ union cqe_st cqe;
+ int rc;
+ u32 *ptr;
+ struct cq_st *cq = cqh;
+ __u32 cons_idx = cq->cons_counter & (cq->num_cqes - 1);
+
+ ptr = (u32 *) (&(cq->cq_buf[cons_idx]));
+ barrier();
+ if ((ptr[7] & 0x80000000) == 0) {
+ cqe = cq->cq_buf[cons_idx];
+ be_to_cpu_buf(&cqe, sizeof(cqe));
+ *cqe_p = cqe;
+ ptr[7] = 0x80000000;
+ barrier();
+ cq->cons_counter++;
+ rc = update_cq_cons_idx(cq);
+ if (rc) {
+ return rc;
+ }
+ *num_cqes = 1;
+ } else
+ *num_cqes = 0;
+
+ return 0;
+}
+
+static void dev2ib_cqe(struct ib_cqe_st *ib_cqe_p, union cqe_st *cqe_p)
+{
+ __u8 opcode;
+ __u32 wqe_addr_ba;
+
+ opcode =
+ EX_FLD(cqe_p->good_cqe, arbelprm_completion_queue_entry_st, opcode);
+ if (opcode >= CQE_ERROR_OPCODE)
+ ib_cqe_p->is_error = 1;
+ else
+ ib_cqe_p->is_error = 0;
+
+ ib_cqe_p->is_send =
+ EX_FLD(cqe_p->good_cqe, arbelprm_completion_queue_entry_st, s);
+ wqe_addr_ba =
+ EX_FLD(cqe_p->good_cqe, arbelprm_completion_queue_entry_st,
+ wqe_adr) << 6;
+ ib_cqe_p->wqe = bus_to_virt(wqe_addr_ba);
+
+ ib_cqe_p->count =
+ EX_FLD(cqe_p->good_cqe, arbelprm_completion_queue_entry_st,
+ byte_cnt);
+}
+
+static int ib_poll_cq(void *cqh, struct ib_cqe_st *ib_cqe_p, u8 * num_cqes)
+{
+ int rc;
+ union cqe_st cqe;
+ struct cq_st *cq = cqh;
+ __u8 opcode;
+
+ rc = poll_cq(cq, &cqe, num_cqes);
+ if (rc || ((*num_cqes) == 0)) {
+ return rc;
+ }
+
+ dev2ib_cqe(ib_cqe_p, &cqe);
+
+ opcode =
+ EX_FLD(cqe.good_cqe, arbelprm_completion_queue_entry_st, opcode);
+ if (opcode >= CQE_ERROR_OPCODE) {
+ struct ud_send_wqe_st *wqe_p, wqe;
+ __u32 *ptr;
+ unsigned int i;
+
+ wqe_p =
+ bus_to_virt(EX_FLD
+ (cqe.error_cqe,
+ arbelprm_completion_with_error_st,
+ wqe_addr) << 6);
+ eprintf("syndrome=0x%lx",
+ EX_FLD(cqe.error_cqe, arbelprm_completion_with_error_st,
+ syndrome));
+ eprintf("vendor_syndrome=0x%lx",
+ EX_FLD(cqe.error_cqe, arbelprm_completion_with_error_st,
+ vendor_code));
+ eprintf("wqe_addr=0x%lx", wqe_p);
+ eprintf("myqpn=0x%lx",
+ EX_FLD(cqe.error_cqe, arbelprm_completion_with_error_st,
+ myqpn));
+ memcpy(&wqe, wqe_p, sizeof wqe);
+ be_to_cpu_buf(&wqe, sizeof wqe);
+
+ eprintf("dumping wqe...");
+ ptr = (__u32 *) (&wqe);
+ for (i = 0; i < sizeof wqe; i += 4) {
+ printf("%lx : ", ptr[i >> 2]);
+ }
+
+ }
+
+ return rc;
+}
+
+/* always work on ipoib qp */
+static int add_qp_to_mcast_group(union ib_gid_u mcast_gid, __u8 add)
+{
+ void *mg;
+ __u8 *tmp;
+ int rc;
+ __u16 mgid_hash;
+ void *mgmqp_p;
+
+ tmp = dev_buffers_p->inprm_buf;
+ memcpy(tmp, mcast_gid.raw, 16);
+ be_to_cpu_buf(tmp, 16);
+ rc = cmd_mgid_hash(tmp, &mgid_hash);
+ if (!rc) {
+ mg = (void *)dev_buffers_p->inprm_buf;
+ memset(mg, 0, MT_STRUCT_SIZE(arbelprm_mgm_entry_st));
+ INS_FLD(mcast_gid.as_u32.dw[0], mg, arbelprm_mgm_entry_st,
+ mgid_128_96);
+ INS_FLD(mcast_gid.as_u32.dw[1], mg, arbelprm_mgm_entry_st,
+ mgid_95_64);
+ INS_FLD(mcast_gid.as_u32.dw[2], mg, arbelprm_mgm_entry_st,
+ mgid_63_32);
+ INS_FLD(mcast_gid.as_u32.dw[3], mg, arbelprm_mgm_entry_st,
+ mgid_31_0);
+ be_to_cpu_buf(mg +
+ MT_BYTE_OFFSET(arbelprm_mgm_entry_st,
+ mgid_128_96), 16);
+ mgmqp_p = mg + MT_BYTE_OFFSET(arbelprm_mgm_entry_st, mgmqp_0);
+ INS_FLD(dev_ib_data.ipoib_qp.qpn, mgmqp_p, arbelprm_mgmqp_st,
+ qpn_i);
+ INS_FLD(add, mgmqp_p, arbelprm_mgmqp_st, qi);
+ rc = cmd_write_mgm(mg, mgid_hash);
+ }
+ return rc;
+}
+
+static int clear_interrupt(void)
+{
+ writel(dev_ib_data.clr_int_data, dev_ib_data.clr_int_addr);
+ return 0;
+}
+
+static struct ud_send_wqe_st *alloc_send_wqe(udqp_t qph)
+{
+ struct udqp_st *qp = qph;
+ __u32 idx;
+
+ if (qp->snd_wqe_cur_free) {
+ qp->snd_wqe_cur_free--;
+ idx = qp->snd_wqe_alloc_idx;
+ qp->snd_wqe_alloc_idx =
+ (qp->snd_wqe_alloc_idx + 1) & (qp->max_snd_wqes - 1);
+ return &qp->snd_wq[idx].wqe_cont.wqe;
+ }
+
+ return NULL;
+}
+
+static struct recv_wqe_st *alloc_rcv_wqe(struct udqp_st *qp)
+{
+ __u32 idx;
+
+ if (qp->recv_wqe_cur_free) {
+ qp->recv_wqe_cur_free--;
+ idx = qp->recv_wqe_alloc_idx;
+ qp->recv_wqe_alloc_idx =
+ (qp->recv_wqe_alloc_idx + 1) & (qp->max_recv_wqes - 1);
+ return &qp->rcv_wq[idx].wqe_cont.wqe;
+ }
+
+ return NULL;
+}
+
+static int free_send_wqe(struct ud_send_wqe_st *wqe)
+{
+ struct udqp_st *qp = ((struct ude_send_wqe_cont_st *)wqe)->qp;
+ qp->snd_wqe_cur_free++;
+
+ return 0;
+}
+
+static int free_rcv_wqe(struct recv_wqe_st *wqe)
+{
+ struct udqp_st *qp = ((struct recv_wqe_cont_st *)wqe)->qp;
+ qp->recv_wqe_cur_free++;
+
+ return 0;
+}
+
+static int free_wqe(void *wqe)
+{
+ int rc = 0;
+ struct recv_wqe_st *rcv_wqe;
+
+// tprintf("free wqe= 0x%x", wqe);
+ if ((wqe >= (void *)(dev_ib_data.ipoib_qp.rcv_wq)) &&
+ (wqe <
+ (void *)(&dev_ib_data.ipoib_qp.rcv_wq[NUM_IPOIB_RCV_WQES]))) {
+ /* ipoib receive wqe */
+ free_rcv_wqe(wqe);
+ rcv_wqe = alloc_rcv_wqe(&dev_ib_data.ipoib_qp);
+ if (rcv_wqe) {
+ rc = post_rcv_buf(&dev_ib_data.ipoib_qp, rcv_wqe);
+ if (rc) {
+ eprintf("");
+ }
+ }
+ } else if (wqe >= (void *)(dev_ib_data.ipoib_qp.snd_wq) &&
+ wqe <
+ (void *)(&dev_ib_data.ipoib_qp.snd_wq[NUM_IPOIB_SND_WQES])) {
+ /* ipoib send wqe */
+ free_send_wqe(wqe);
+ } else if (wqe >= (void *)(dev_ib_data.mads_qp.rcv_wq) &&
+ wqe <
+ (void *)(&dev_ib_data.mads_qp.rcv_wq[NUM_MADS_RCV_WQES])) {
+ /* mads receive wqe */
+ free_rcv_wqe(wqe);
+ rcv_wqe = alloc_rcv_wqe(&dev_ib_data.mads_qp);
+ if (rcv_wqe) {
+ rc = post_rcv_buf(&dev_ib_data.mads_qp, rcv_wqe);
+ if (rc) {
+ eprintf("");
+ }
+ }
+ } else if (wqe >= (void *)(dev_ib_data.mads_qp.snd_wq) &&
+ wqe <
+ (void *)(&dev_ib_data.mads_qp.snd_wq[NUM_MADS_SND_WQES])) {
+ /* mads send wqe */
+ free_send_wqe(wqe);
+ } else {
+ rc = -1;
+ eprintf("");
+ }
+
+ return rc;
+}
+
+static int update_eq_cons_idx(struct eq_st *eq)
+{
+ writel(eq->cons_counter, eq->ci_base_base_addr);
+ return 0;
+}
+
+static void dev2ib_eqe(struct ib_eqe_st *ib_eqe_p, struct eqe_t *eqe_p)
+{
+ void *tmp;
+
+ ib_eqe_p->event_type =
+ EX_FLD(eqe_p, arbelprm_event_queue_entry_st, event_type);
+
+ tmp = eqe_p + MT_BYTE_OFFSET(arbelprm_event_queue_entry_st, event_data);
+ ib_eqe_p->cqn = EX_FLD(tmp, arbelprm_completion_event_st, cqn);
+}
+
+static int poll_eq(struct ib_eqe_st *ib_eqe_p, __u8 * num_eqes)
+{
+ struct eqe_t eqe;
+ u8 owner;
+ int rc;
+ u32 *ptr;
+ struct eq_st *eq = &dev_ib_data.eq;
+ __u32 cons_idx = eq->cons_counter & (eq->eq_size - 1);
+
+ ptr = (u32 *) (&(eq->eq_buf[cons_idx]));
+ owner = (ptr[7] & 0x80000000) ? OWNER_HW : OWNER_SW;
+ if (owner == OWNER_SW) {
+ eqe = eq->eq_buf[cons_idx];
+ be_to_cpu_buf(&eqe, sizeof(eqe));
+ dev2ib_eqe(ib_eqe_p, &eqe);
+ ptr[7] |= 0x80000000;
+ eq->eq_buf[cons_idx] = eqe;
+ eq->cons_counter++;
+ rc = update_eq_cons_idx(eq);
+ if (rc) {
+ return -1;
+ }
+ *num_eqes = 1;
+ } else {
+ *num_eqes = 0;
+ }
+ return 0;
+}
+
+static int ib_device_close(void)
+{
+ iounmap(memfree_pci_dev.uar);
+ iounmap(memfree_pci_dev.cr_space);
+ return 0;
+}
+
+static __u32 dev_get_qpn(void *qph)
+{
+ struct udqp_st *qp = qph;
+
+ return qp->qpn;
+}
+
+static void dev_post_dbell(void *dbell, __u32 offset)
+{
+ __u32 *ptr;
+ unsigned long address;
+
+ ptr = dbell;
+
+ if (((ptr[0] >> 24) & 0xff) != 1) {
+ eprintf("");
+ }
+ tprintf("ptr[0]= 0x%lx", ptr[0]);
+ tprintf("ptr[1]= 0x%lx", ptr[1]);
+ address = (unsigned long)(memfree_pci_dev.uar) + offset;
+ tprintf("va=0x%lx pa=0x%lx", address,
+ virt_to_bus((const void *)address));
+ writel(htonl(ptr[0]), memfree_pci_dev.uar + offset);
+ barrier();
+ address += 4;
+ tprintf("va=0x%lx pa=0x%lx", address,
+ virt_to_bus((const void *)address));
+ writel(htonl(ptr[1]), address /*memfree_pci_dev.uar + offset + 4 */ );
+}
diff --git a/src/drivers/net/mlx_ipoib/ipoib.c b/src/drivers/net/mlx_ipoib/ipoib.c
new file mode 100644
index 000000000..85eaac7aa
--- /dev/null
+++ b/src/drivers/net/mlx_ipoib/ipoib.c
@@ -0,0 +1,1027 @@
+/*
+ This software is available to you under a choice of one of two
+ licenses. You may choose to be licensed under the terms of the GNU
+ General Public License (GPL) Version 2, available at
+ <http://www.fsf.org/copyleft/gpl.html>, or the OpenIB.org BSD
+ license, available in the LICENSE.TXT file accompanying this
+ software. These details are also available at
+ <http://openib.org/license.html>.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+
+ Copyright (c) 2004 Mellanox Technologies Ltd. All rights reserved.
+*/
+
+#include "ipoib.h"
+#include "ib_driver.h"
+#include "ib_mad.h"
+
+static const __u8 arp_packet_template[] = {
+ 0x00, 0x20, /* hardware type */
+ 0x08, 0x00, /* protocol type */
+ 20, /* hw size */
+ 4, /* protocol size */
+ 0x00, 0x00, /* opcode */
+
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, /* sender's mac */
+ 0, 0, 0, 0, /* sender's IP address */
+
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, /* Target's mac */
+ 0, 0, 0, 0 /* targets's IP address */
+};
+
+struct ipoib_data_st {
+ __u32 ipoib_qpn;
+ udqp_t ipoib_qph;
+ ud_av_t bcast_av;
+ cq_t snd_cqh;
+ cq_t rcv_cqh;
+ __u8 *port_gid_raw;
+} ipoib_data;
+
+#define NUM_MAC_ENTRIES (NUM_AVS+2)
+
+static struct mac_xlation_st mac_tbl[NUM_MAC_ENTRIES];
+static __u32 mac_counter = 1;
+static __u32 youth_counter = 0;
+
+#define EQUAL_GUIDS(g1, g2) ( \
+ ((g1)[0]==(g2)[0]) && \
+ ((g1)[1]==(g2)[1]) && \
+ ((g1)[2]==(g2)[2]) && \
+ ((g1)[3]==(g2)[3]) && \
+ ((g1)[4]==(g2)[4]) && \
+ ((g1)[5]==(g2)[5]) && \
+ ((g1)[6]==(g2)[6]) && \
+ ((g1)[7]==(g2)[7]) )
+
+#define MAC_IDX(i) (((mac_tbl[i].eth_mac_lsb[0])<<16) | \
+ ((mac_tbl[i].eth_mac_lsb[0])<<8) | \
+ (mac_tbl[i].eth_mac_lsb[0]))
+
+static inline const void *qpn2buf(__u32 qpn, const void *buf)
+{
+ ((__u8 *) buf)[0] = qpn >> 16;
+ ((__u8 *) buf)[1] = (qpn >> 8) & 0xff;
+ ((__u8 *) buf)[2] = qpn & 0xff;
+ return buf;
+}
+
+static inline __u32 buf2qpn(const void *buf)
+{
+ __u32 qpn;
+
+ qpn = ((((__u8 *) buf)[0]) << 16) +
+ ((((__u8 *) buf)[1]) << 8) + (((__u8 *) buf)[2]);
+
+ return qpn;
+}
+
+static int is_bcast_mac(const char *dest)
+{
+ int i;
+ __u8 mac = 0xff;
+
+ for (i = 0; i < 6; ++i)
+ mac &= dest[i];
+
+ return mac == 0xff;
+}
+
+/* find a free entry. if not found kick
+ * another entry.
+ */
+static int find_free_entry(void)
+{
+ __u32 youth = 0xffffffff;
+ __u8 i, remove_idx = NUM_MAC_ENTRIES;
+
+ /* find a free entry */
+ for (i = 0; i < NUM_MAC_ENTRIES; ++i) {
+ if (!mac_tbl[i].valid) {
+ mac_tbl[i].valid = 1;
+ mac_tbl[i].youth = youth_counter;
+ youth_counter++;
+ return i;
+ }
+ }
+
+ for (i = 0; i < NUM_MAC_ENTRIES; ++i) {
+ if ((mac_tbl[i].av == NULL) && (mac_tbl[i].youth < youth)) {
+ youth = mac_tbl[i].youth;
+ remove_idx = i;
+ }
+ }
+
+ if (remove_idx < NUM_MAC_ENTRIES) {
+ /* update the new youth value */
+ mac_tbl[remove_idx].youth = youth_counter;
+ youth_counter++;
+ return remove_idx;
+ } else {
+ tprintf("did not find an entry to kick");
+ return -1;
+ }
+}
+
+static int find_qpn_gid(__u32 qpn, const __u8 * gid)
+{
+ __u16 i;
+
+ for (i = 0; i < NUM_MAC_ENTRIES; ++i) {
+ if (mac_tbl[i].valid &&
+ (mac_tbl[i].qpn == qpn) &&
+ !memcmp(mac_tbl[i].gid.raw, gid, 16)) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+static void allocate_new_mac6(__u8 * mac_lsb)
+{
+ __u32 eth_counter;
+
+ eth_counter = mac_counter;
+ mac_counter = (mac_counter + 1) & 0xffffff;
+
+ mac_lsb[0] = eth_counter >> 16;
+ mac_lsb[1] = eth_counter >> 8;
+ mac_lsb[2] = eth_counter & 0xff;
+ tprintf("add mac: %x:%x:%x", mac_lsb[0], mac_lsb[1], mac_lsb[2]);
+}
+
+static void modify_arp_reply(__u8 * eth_mac_lsb, void *data)
+{
+ __u8 *packet;
+
+ /* skip 4 bytes */
+ packet = ((__u8 *) data) + 4;
+
+ /* modify hw type */
+ packet[0] = 0;
+ packet[1] = 1;
+
+ /* modify hw size */
+ packet[4] = 6;
+
+ /* modify sender's mac */
+ packet[8] = MLX_ETH_BYTE0;
+ packet[9] = MLX_ETH_BYTE1;
+ packet[10] = MLX_ETH_BYTE2;
+ packet[11] = eth_mac_lsb[0];
+ packet[12] = eth_mac_lsb[1];
+ packet[13] = eth_mac_lsb[2];
+
+ /* move sender's IP address */
+ memcpy(packet + 14, packet + 28, 4);
+
+ /* set target MAC - that's us */
+ packet[18] = MLX_ETH_BYTE0;
+ packet[19] = MLX_ETH_BYTE1;
+ packet[20] = MLX_ETH_BYTE2;
+ packet[21] = 0;
+ packet[22] = 0;
+ packet[23] = 0;
+
+ /* move target's IP address */
+ memcpy(packet + 24, packet + 52, 4);
+}
+
+static void modify_arp_request(__u8 * eth_mac_lsb, void *data)
+{
+ __u8 *packet;
+
+ /* skip 4 bytes */
+ packet = ((__u8 *) data) + 4;
+
+ /* modify hw type */
+ packet[0] = 0;
+ packet[1] = 1;
+
+ /* modify hw size */
+ packet[4] = 6;
+
+ /* modify sender's mac */
+ packet[8] = MLX_ETH_BYTE0;
+ packet[9] = MLX_ETH_BYTE1;
+ packet[10] = MLX_ETH_BYTE2;
+ packet[11] = eth_mac_lsb[0];
+ packet[12] = eth_mac_lsb[1];
+ packet[13] = eth_mac_lsb[2];
+
+ /* move sender's IP address */
+ memcpy(packet + 14, packet + 28, 4);
+
+ /* set target MAC - that's us */
+ packet[18] = 0;
+ packet[19] = 0;
+ packet[20] = 0;
+ packet[21] = 0;
+ packet[22] = 0;
+ packet[23] = 0;
+
+ /* move target's IP address */
+ memcpy(packet + 24, packet + 52, 4);
+}
+
+static int handle_arp_packet(void *buf, void **out_buf_p,
+ unsigned int *new_size_p)
+{
+ __u16 opcode;
+ const void *p;
+ const __u8 *gid;
+ __u32 qpn;
+ int idx;
+
+ opcode = get_opcode(buf);
+ switch (opcode) {
+ case ARP_OP_REQUESET:
+ case ARP_OP_REPLY:
+ break;
+
+ default:
+ return -1;
+ }
+
+ p = arp_mac20_get_sender_qpn(buf);
+ qpn = buf2qpn(p);
+ gid = arp_mac20_get_sender_gid(buf);
+
+ if (!memcmp(gid, get_port_gid(), 16)) {
+ /* my own gid */
+ *out_buf_p = NULL;
+ return 0;
+ }
+
+ idx = find_qpn_gid(qpn, gid);
+ if (idx == -1) {
+ /* entry not in the table */
+ idx = find_free_entry();
+ if (idx == -1) {
+ eprintf("we're in broch\n");
+ return -1;
+ }
+ allocate_new_mac6(mac_tbl[idx].eth_mac_lsb);
+ mac_tbl[idx].av = NULL; // free the av id it exists ?? !!
+ mac_tbl[idx].qpn = qpn;
+ memcpy(mac_tbl[idx].gid.raw, gid, 16);
+ }
+
+ if (opcode == ARP_OP_REQUESET) {
+ modify_arp_request(mac_tbl[idx].eth_mac_lsb, buf);
+ } else {
+ /* we want to filter possible broadcast arp
+ replies not directed to us */
+ p = arp_mac20_get_target_qpn(buf);
+ qpn = buf2qpn(p);
+ gid = arp_mac20_get_target_gid(buf);
+
+ if ((qpn != ipoib_data.ipoib_qpn) ||
+ (memcmp(gid, get_port_gid(), 16))) {
+ *out_buf_p = NULL;
+ return 0;
+ }
+
+ modify_arp_reply(mac_tbl[idx].eth_mac_lsb, buf);
+ {
+ __u8 i;
+ tprintf("arp reply dump:\n");
+ for (i = 4; i < 32; ++i) {
+ tprintf("%x: ", ((__u8 *) buf)[i]);
+ }
+ tprintf("\n");
+ }
+ }
+ *out_buf_p = ((__u8 *) buf) + 4;
+ *new_size_p = 28; /* size of eth arp packet */
+
+ tprintf("");
+
+ return 0;
+}
+
+static void modify_udp_csum(void *buf, __u16 size)
+{
+ __u8 *ptr = (__u8 *) buf;
+ __u32 csum = 0;
+ __u16 chksum;
+ __u16 buf_size;
+ __u16 *tmp;
+ int i;
+
+ buf_size = (size & 1) ? size + 1 : size;
+ tmp = (__u16 *) (ptr + 12); /* src and dst ip addresses */
+ for (i = 0; i < 4; ++i) {
+ csum += tmp[i];
+ }
+
+ csum += 0x1100; // udp protocol
+
+ tmp = (__u16 *) (ptr + 26);
+ tmp[0] = 0; /* zero the checksum */
+
+ tmp = (__u16 *) (ptr + 24);
+ csum += tmp[0];
+
+ tmp = (__u16 *) (ptr + 20);
+
+ for (i = 0; i < ((buf_size - 20) >> 1); ++i) {
+ csum += tmp[i];
+ }
+
+ chksum = ~((__u16) ((csum & 0xffff) + (csum >> 16)));
+
+ tmp = (__u16 *) (ptr + 26);
+ tmp[0] = chksum; /* set the checksum */
+}
+
+static void modify_dhcp_resp(void *buf, __u16 size)
+{
+ set_eth_hwtype(buf);
+ set_eth_hwlen(buf);
+ set_own_mac(buf);
+ modify_udp_csum(buf, size);
+}
+
+static void get_my_client_id(__u8 * my_client_id)
+{
+
+ my_client_id[0] = 0;
+ qpn2buf(ipoib_data.ipoib_qpn, my_client_id + 1);
+ memcpy(my_client_id + 4, ipoib_data.port_gid_raw, 16);
+}
+
+static const __u8 *get_client_id(const void *buf, int len)
+{
+ const __u8 *ptr;
+ int delta;
+
+ if (len < 268)
+ return NULL;
+
+ /* pointer to just after magic cookie */
+ ptr = (const __u8 *)buf + 268;
+
+ /* find last client identifier option */
+ do {
+ if (ptr[0] == 255) {
+ /* found end of options list */
+ return NULL;
+ }
+
+ if (ptr[0] == 0x3d) {
+ /* client identifer option */
+ return ptr + 3;
+ }
+
+ delta = ptr[1] + 2;
+ ptr += delta;
+ len -= delta;
+ } while (len > 0);
+
+ return NULL;
+}
+
+static int handle_ipv4_packet(void *buf, void **out_buf_p,
+ unsigned int *new_size_p, int *is_bcast_p)
+{
+ void *new_buf;
+ __u16 new_size;
+ __u8 msg_type;
+ __u8 my_client_id[20];
+
+ new_buf = (void *)(((__u8 *) buf) + 4);
+ new_size = (*new_size_p) - 4;
+ *out_buf_p = new_buf;
+ *new_size_p = new_size;
+
+ if (get_ip_protocl(new_buf) == IP_PROT_UDP) {
+ __u16 udp_dst_port;
+ const __u8 *client_id;
+
+ udp_dst_port = get_udp_dst_port(new_buf);
+
+ if (udp_dst_port == 67) {
+ /* filter dhcp requests */
+ *out_buf_p = 0;
+ return 0;
+ }
+
+ if (udp_dst_port == 68) {
+ get_my_client_id(my_client_id);
+
+ /* packet client id */
+ client_id = get_client_id(new_buf, new_size);
+ if (!client_id) {
+ *out_buf_p = 0;
+ return 0;
+ }
+
+ if (memcmp(client_id, my_client_id, 20)) {
+ *out_buf_p = 0;
+ return 0;
+ }
+ }
+ }
+
+ msg_type = get_dhcp_msg_type(new_buf);
+ if ((get_ip_protocl(new_buf) == IP_PROT_UDP) &&
+ (get_udp_dst_port(new_buf) == 68) &&
+ ((msg_type == DHCP_TYPE_RESPONSE) || (msg_type == DHCP_TYPE_ACK))
+ ) {
+ *is_bcast_p = 1;
+ modify_dhcp_resp(new_buf, new_size);
+ }
+
+ return 0;
+}
+
+static int is_valid_arp(void *buf, unsigned int size)
+{
+ __u8 *ptr = buf;
+ __u16 tmp;
+
+ if (size != 60) {
+ eprintf("");
+ return 0;
+ }
+ if (be16_to_cpu(*((__u16 *) ptr)) != ARP_PROT_TYPE)
+ return 0;
+
+ if (be16_to_cpu(*((__u16 *) (ptr + 4))) != IPOIB_HW_TYPE)
+ return 0;
+
+ if (be16_to_cpu(*((__u16 *) (ptr + 6))) != IPV4_PROT_TYPE)
+ return 0;
+
+ if (ptr[8] != 20) /* hw addr len */
+ return 0;
+
+ if (ptr[9] != 4) /* protocol len = 4 for IP */
+ return 0;
+
+ tmp = be16_to_cpu(*((__u16 *) (ptr + 10)));
+ if ((tmp != ARP_OP_REQUESET) && (tmp != ARP_OP_REPLY))
+ return 0;
+
+ return 1;
+}
+
+static int ipoib_handle_rcv(void *buf, void **out_buf_p,
+ unsigned int *new_size_p, int *is_bcast_p)
+{
+ __u16 prot_type;
+ int rc;
+
+ prot_type = get_prot_type(buf);
+ switch (prot_type) {
+ case ARP_PROT_TYPE:
+ tprintf("");
+ if (is_valid_arp(buf, *new_size_p)) {
+ tprintf("got valid arp");
+ rc = handle_arp_packet(buf, out_buf_p, new_size_p);
+ if (rc) {
+ eprintf("");
+ return rc;
+ }
+ if (!out_buf_p) {
+ tprintf("");
+ }
+ tprintf("arp for me");
+ *is_bcast_p = 1;
+ return rc;
+ } else {
+ tprintf("got invalid arp");
+ *out_buf_p = NULL;
+ return 0;
+ }
+
+ case IPV4_PROT_TYPE:
+ tprintf("");
+ rc = handle_ipv4_packet(buf, out_buf_p, new_size_p, is_bcast_p);
+ return rc;
+ }
+ eprintf("prot=0x%x", prot_type);
+ return -1;
+}
+
+static int is_null_mac(const __u8 * mac)
+{
+ __u8 i, tmp = 0;
+ __u8 lmac[6];
+
+ memcpy(lmac, mac, 6);
+
+ for (i = 0; i < 6; ++i) {
+ tmp |= lmac[i];
+ }
+
+ if (tmp == 0)
+ return 1;
+ else
+ return 0;
+}
+
+static int find_mac(const __u8 * mac)
+{
+ int i;
+ const __u8 *tmp = mac + 3;
+
+ for (i = 0; i < NUM_MAC_ENTRIES; ++i) {
+ tprintf("checking 0x%02x:0x%02x:0x%02x valid=%d",
+ mac_tbl[i].eth_mac_lsb[0], mac_tbl[i].eth_mac_lsb[1],
+ mac_tbl[i].eth_mac_lsb[2], mac_tbl[i].valid);
+ if (mac_tbl[i].valid && !memcmp(mac_tbl[i].eth_mac_lsb, tmp, 3))
+ return i;
+ }
+ tprintf("mac: %x:%x:%x - dumping", tmp[0], tmp[1], tmp[2]);
+ for (i = 0; i < NUM_MAC_ENTRIES; ++i) {
+ //__u8 *gid= mac_tbl[i].gid.raw;
+ //__u8 *m= mac_tbl[i].eth_mac_lsb;
+ /*if (mac_tbl[i].valid) {
+ tprintf("%d: qpn=0x%lx, "
+ "gid=%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x, "
+ "av=0x%lx, "
+ "youth= %ld, "
+ "mac=%x:%x:%x\n",
+ i, mac_tbl[i].qpn,
+ gid[0], gid[1], gid[2], gid[3], gid[4], gid[5], gid[6], gid[7],
+ gid[8], gid[9], gid[10], gid[11], gid[12], gid[13], gid[14], gid[15],
+ mac_tbl[i].av, mac_tbl[i].youth,
+ m[0], m[1], m[2]);
+ } */
+ }
+ return -1;
+}
+
+static int send_bcast_packet(__u16 protocol, const void *data, __u16 size)
+{
+ ud_send_wqe_t snd_wqe, tmp_wqe;
+ int rc;
+ int is_good;
+ void *send_buffer;
+
+ snd_wqe = alloc_send_wqe(ipoib_data.ipoib_qph);
+ if (!snd_wqe) {
+ eprintf("");
+ return -1;
+ }
+
+ send_buffer = get_send_wqe_buf(snd_wqe, 0);
+ *((__u32 *) send_buffer) = cpu_to_be32(protocol << 16);
+ prep_send_wqe_buf(ipoib_data.ipoib_qph, ipoib_data.bcast_av,
+ snd_wqe, data, 4, size, 0);
+
+ rc = post_send_req(ipoib_data.ipoib_qph, snd_wqe, 1);
+ if (rc) {
+ eprintf("");
+ goto ex;
+ }
+
+ rc = poll_cqe_tout(ipoib_data.snd_cqh, SEND_CQE_POLL_TOUT, &tmp_wqe,
+ &is_good);
+ if (rc) {
+ eprintf("");
+ goto ex;
+ }
+ if (!is_good) {
+ eprintf("");
+ rc = -1;
+ goto ex;
+ }
+ if (tmp_wqe != snd_wqe) {
+ eprintf("");
+ rc = -1;
+ goto ex;
+ }
+
+ ex:free_wqe(snd_wqe);
+ return rc;
+}
+
+static int send_ucast_packet(const __u8 * mac, __u16 protocol, const void *data,
+ __u16 size)
+{
+ ud_send_wqe_t snd_wqe, tmp_wqe;
+ ud_av_t av;
+ udqp_t qph;
+ __u16 dlid;
+ __u8 sl, rate;
+ int rc;
+ int i;
+ int is_good;
+
+ i = find_mac(mac);
+ if (i < 0) {
+ tprintf("");
+ return -1;
+ }
+
+ if (!mac_tbl[i].av) {
+ rc = get_path_record(&mac_tbl[i].gid, &dlid, &sl, &rate);
+ if (rc) {
+ eprintf("");
+ return -1;
+ } else {
+ tprintf("get_path_record() success dlid=0x%x", dlid);
+ }
+
+ /* no av - allocate one */
+ av = alloc_ud_av();
+ if (!av) {
+ eprintf("");
+ return -1;
+ }
+ modify_av_params(av, dlid, 1, sl, rate, &mac_tbl[i].gid,
+ mac_tbl[i].qpn);
+ mac_tbl[i].av = av;
+ } else {
+ av = mac_tbl[i].av;
+ }
+ qph = ipoib_data.ipoib_qph;
+ snd_wqe = alloc_send_wqe(qph);
+ if (!snd_wqe) {
+ eprintf("");
+ return -1;
+ }
+
+ *((__u32 *) get_send_wqe_buf(snd_wqe, 0)) = cpu_to_be32(protocol << 16);
+ prep_send_wqe_buf(qph, av, snd_wqe, data, 4, size, 0);
+
+ rc = post_send_req(qph, snd_wqe, 1);
+ if (rc) {
+ eprintf("");
+ return -1;
+ }
+
+ rc = poll_cqe_tout(ipoib_data.snd_cqh, SEND_CQE_POLL_TOUT, &tmp_wqe,
+ &is_good);
+ if (rc) {
+ eprintf("");
+ goto ex;
+ }
+ if (!is_good) {
+ eprintf("");
+ rc = -1;
+ goto ex;
+ }
+ if (tmp_wqe != snd_wqe) {
+ eprintf("");
+ rc = -1;
+ goto ex;
+ }
+
+ ex:free_wqe(snd_wqe);
+ return rc;
+}
+
+static void *alloc_convert_arp6_msg(const void *data,
+ struct arp_packet_st *ipoib_arp)
+{
+ void *buf;
+ const void *p1;
+ int idx;
+ __u8 qpn[3];
+
+ memcpy(ipoib_arp, arp_packet_template, sizeof arp_packet_template);
+ buf = ipoib_arp;
+
+ /* update opcode */
+ p1 = arp_mac6_get_opcode(data);
+ arp_mac20_set_opcode(p1, buf);
+
+ /* update sender ip */
+ p1 = arp_mac6_get_sender_ip(data);
+ arp_mac20_set_sender_ip(p1, buf);
+
+ /* update target ip */
+ p1 = arp_mac6_get_target_ip(data);
+ arp_mac20_set_target_ip(p1, buf);
+
+ /* update sender mac */
+ qpn2buf(ipoib_data.ipoib_qpn, qpn);
+ arp_mac20_set_sender_mac(qpn, ipoib_data.port_gid_raw, buf);
+
+ /* update target mac */
+ p1 = arp_mac6_get_target_mac(data);
+ if (!is_null_mac(p1)) {
+ idx = find_mac(p1);
+ if (idx == -1) {
+ __u8 *_ptr = (__u8 *) p1;
+ eprintf("could not find mac %x:%x:%x",
+ _ptr[3], _ptr[4], _ptr[5]);
+ return NULL;
+ }
+ qpn2buf(mac_tbl[idx].qpn, qpn);
+ arp_mac20_set_target_mac(qpn, mac_tbl[idx].gid.raw, buf);
+ }
+
+ return buf;
+}
+
+static __u16 set_client_id(__u8 * packet)
+{
+ __u8 *ptr;
+ __u8 y[3];
+ __u16 new_size;
+
+ /* pointer to just after magic cookie */
+ ptr = packet + 268;
+
+ /* find last option */
+ do {
+ if (ptr[0] == 255) {
+ /* found end of options list */
+ break;
+ }
+ ptr = ptr + ptr[1] + 2;
+ } while (1);
+
+ ptr[0] = 61; /* client id option identifier */
+ ptr[1] = 21; /* length of the option */
+ ptr[2] = IPOIB_HW_TYPE;
+ ptr[3] = 0;
+ qpn2buf(ipoib_data.ipoib_qpn, y);
+ memcpy(ptr + 4, y, 3);
+ memcpy(ptr + 7, ipoib_data.port_gid_raw, 16);
+ ptr[23] = 255;
+ new_size = (__u16) (ptr + 24 - packet);
+ if (new_size & 3) {
+ new_size += (4 - (new_size & 3));
+ }
+ return new_size;
+}
+
+static __u16 calc_udp_csum(__u8 * packet)
+{
+ __u16 *ptr;
+ int i;
+ __u32 sum = 0;
+ __u16 udp_length, udp_csum;
+
+ /* src ip, dst ip */
+ ptr = (__u16 *) (packet + 12);
+ for (i = 0; i < 4; ++i) {
+ sum += be16_to_cpu(ptr[i]);
+ }
+
+ /* udp protocol */
+ sum += IP_PROT_UDP;
+
+ /* udp length */
+ ptr = (__u16 *) (packet + 24);
+ udp_length = be16_to_cpu(*ptr);
+ sum += udp_length;
+
+ /* udp part */
+ ptr = (__u16 *) (packet + 20);
+ do {
+ sum += be16_to_cpu(*ptr);
+ ptr++;
+ udp_length -= 2;
+ } while (udp_length);
+
+ udp_csum = ~((__u16) ((sum & 0xffff) + (sum >> 16)));
+ return udp_csum;
+}
+
+static __u16 modify_dhcp_request(__u8 * packet, __u16 size)
+{
+ __u16 csum, new_size;
+
+ set_hw_type(packet);
+ zero_hw_len(packet);
+ zero_chaddr(packet);
+ set_bcast_flag(packet);
+ new_size = set_client_id(packet);
+ if (new_size > size) {
+ add_udp_len(packet, new_size - size);
+ } else
+ new_size = size;
+ set_udp_csum(packet, 0);
+ csum = calc_udp_csum(packet);
+ set_udp_csum(packet, csum);
+ return new_size;
+}
+
+static __u16 copy_dhcp_message(__u8 * buf, const void *packet, __u16 size)
+{
+ memcpy(buf, packet, size);
+ return size;
+}
+
+static void modify_ip_hdr(__u8 * buf, __u16 add_size)
+{
+ __u16 *ptr, ip_csum;
+ __u16 tmp;
+ __u32 sum = 0;
+ __u8 i;
+
+ /* update ip length */
+ ptr = (__u16 *) buf;
+ tmp = be16_to_cpu(ptr[1]);
+ ptr[1] = cpu_to_be16(tmp + add_size);
+
+ ptr[5] = 0; /* zero csum */
+ for (i = 0; i < 10; ++i) {
+ sum += be16_to_cpu(ptr[i]);
+ }
+
+ ip_csum = ~((__u16) ((sum & 0xffff) + (sum >> 16)));
+ ptr[5] = cpu_to_be16(ip_csum);
+
+}
+
+static void *update_dhcp_request(const void *packet, unsigned int size,
+ __u16 * new_size_p)
+{
+ __u8 ip_proto, dhcp_message_type;
+ __u16 dest_port, new_size, orig_size;
+ static __u8 dhcp_send_buffer[576];
+
+ ip_proto = get_ip_protocl_type(packet);
+ if (ip_proto != IP_PROT_UDP) {
+ return NULL;
+ }
+
+ dest_port = get_udp_dest_port(packet);
+ if (dest_port != 0x4300 /*67 */ )
+ return NULL;
+
+ dhcp_message_type = get_dhcp_message_type(packet);
+ if (dhcp_message_type != DHCP_TYPE_REQUEST)
+ return NULL;
+
+ memset(dhcp_send_buffer, 0, sizeof dhcp_send_buffer);
+ orig_size = copy_dhcp_message(dhcp_send_buffer, packet, size);
+
+ new_size = modify_dhcp_request(dhcp_send_buffer, orig_size);
+ if (new_size != orig_size) {
+ modify_ip_hdr(dhcp_send_buffer, new_size - orig_size);
+ }
+ *new_size_p = new_size;
+ return dhcp_send_buffer;
+}
+
+static int ipoib_send_packet(const __u8 * mac, __u16 protocol, const void *data,
+ unsigned int size)
+{
+ const void *packet;
+ __u16 new_size, dhcp_req_sz;
+ void *tmp;
+ int rc;
+ struct arp_packet_st ipoib_arp;
+
+ tprintf("");
+
+ if (protocol == ARP_PROT_TYPE) {
+ /* special treatment for ARP */
+ tmp = alloc_convert_arp6_msg(data, &ipoib_arp);
+ if (!tmp) {
+ eprintf("");
+ return -1;
+ }
+ packet = tmp;
+ new_size = sizeof(struct arp_packet_st);
+ tprintf("sending arp");
+ } else {
+ tmp = update_dhcp_request(data, size, &dhcp_req_sz);
+ if (tmp) {
+ /* it was a dhcp request so we use a special
+ buffer because we may have to enlarge the size of the packet */
+ tprintf("sending dhcp");
+ packet = tmp;
+ new_size = dhcp_req_sz;
+ } else {
+ packet = data;
+ new_size = size;
+ tprintf("sending packet");
+ }
+ }
+
+ //eprintf("press key ..."); getchar();
+ if (is_bcast_mac(mac)) {
+ tprintf("");
+ rc = send_bcast_packet(protocol, packet, new_size);
+ } else {
+ tprintf("");
+ rc = send_ucast_packet(mac, protocol, packet, new_size);
+ }
+
+ return rc;
+}
+
+static int ipoib_read_packet(__u16 * prot_p, void *data, unsigned int *size_p,
+ int *is_bcast_p)
+{
+ int rc;
+ struct ib_cqe_st ib_cqe;
+ __u8 num_cqes;
+ unsigned int new_size;
+ void *buf, *out_buf;
+ __u16 prot_type;
+
+ rc = ib_poll_cq(ipoib_data.rcv_cqh, &ib_cqe, &num_cqes);
+ if (rc) {
+ return rc;
+ }
+
+ if (num_cqes == 0) {
+ *size_p = 0;
+ return 0;
+ }
+
+ if (ib_cqe.is_error) {
+ eprintf("");
+ rc = -1;
+ goto ex_func;
+ }
+
+ new_size = ib_cqe.count - GRH_SIZE;
+ buf = get_rcv_wqe_buf(ib_cqe.wqe, 1);
+ tprintf("buf=%lx", buf);
+ rc = ipoib_handle_rcv(buf, &out_buf, &new_size, is_bcast_p);
+ if (rc) {
+ eprintf("");
+ rc = -1;
+ goto ex_func;
+ }
+ if (out_buf) {
+ tprintf("");
+ prot_type = get_prot_type(buf);
+ *size_p = new_size;
+ tprintf("new_size=%d", new_size);
+ if (new_size > 1560) {
+ eprintf("sizzzzzze = %d", new_size);
+ } else {
+ memcpy(data, out_buf, new_size);
+ }
+ *prot_p = prot_type;
+ } else {
+ tprintf("skip message");
+ *size_p = 0;
+ }
+
+ ex_func:
+ if (free_wqe(ib_cqe.wqe)) {
+ eprintf("");
+ }
+
+ return rc;
+}
+
+static int ipoib_init(struct pci_device *pci)
+{
+ int rc;
+ udqp_t qph;
+ int i;
+
+ tprintf("");
+ rc = ib_driver_init(pci, &qph);
+ if (rc)
+ return rc;
+
+ tprintf("");
+ ipoib_data.ipoib_qph = qph;
+ ipoib_data.ipoib_qpn = ib_get_qpn(qph);
+
+ if(print_info)
+ printf("local ipoib qpn=0x%x\n", ipoib_data.ipoib_qpn);
+
+ ipoib_data.bcast_av = ib_data.bcast_av;
+ ipoib_data.port_gid_raw = ib_data.port_gid.raw;
+ ipoib_data.snd_cqh = ib_data.ipoib_snd_cq;
+ ipoib_data.rcv_cqh = ib_data.ipoib_rcv_cq;
+
+ mac_counter = 1;
+ youth_counter = 0;
+ for (i = 0; i < NUM_MAC_ENTRIES; ++i) {
+ mac_tbl[i].valid = 0;
+ mac_tbl[i].av = NULL;
+ }
+
+ return 0;
+}
+
+static int ipoib_close(int fw_fatal)
+{
+ int rc;
+
+ rc = ib_driver_close(fw_fatal);
+
+ return rc;
+}
diff --git a/src/drivers/net/mlx_ipoib/ipoib.h b/src/drivers/net/mlx_ipoib/ipoib.h
new file mode 100644
index 000000000..c51f8a50d
--- /dev/null
+++ b/src/drivers/net/mlx_ipoib/ipoib.h
@@ -0,0 +1,297 @@
+/*
+ This software is available to you under a choice of one of two
+ licenses. You may choose to be licensed under the terms of the GNU
+ General Public License (GPL) Version 2, available at
+ <http://www.fsf.org/copyleft/gpl.html>, or the OpenIB.org BSD
+ license, available in the LICENSE.TXT file accompanying this
+ software. These details are also available at
+ <http://openib.org/license.html>.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+
+ Copyright (c) 2004 Mellanox Technologies Ltd. All rights reserved.
+*/
+
+#ifndef __ipoib_h__
+#define __ipoib_h__
+
+#define ARP_PROT_TYPE 0x806
+#define IPV4_PROT_TYPE 0x800
+
+#define IPOIB_HW_TYPE 0x20
+#define ETH_HW_TYPE 1
+
+#define ARP_OP_REQUESET 1
+#define ARP_OP_REPLY 2
+
+#define MLX_ETH_3BYTE_PREFIX 0x2c9 /* 00,02,c9 */
+#define MLX_ETH_BYTE0 0
+#define MLX_ETH_BYTE1 2
+#define MLX_ETH_BYTE2 0xC9
+
+#define IP_PROT_UDP 17
+#define DHCP_TYPE_REQUEST 1
+#define DHCP_TYPE_RESPONSE 2
+#define DHCP_TYPE_ACK 5
+
+struct ipoib_mac_st {
+ __u32 qpn:24;
+ __u32 r0:8;
+ __u8 gid[16];
+} __attribute__ ((packed));
+
+struct arp_packet_st {
+ __u16 arp_prot_type;
+ __u16 hw_type;
+ __u16 opcode;
+ __u8 prot_size;
+ __u8 hw_len;
+ struct ipoib_mac_st sender_mac;
+ __u32 sender_ip;
+ struct ipoib_mac_st target_mac;
+ __u32 target_ip;
+} __attribute__ ((packed));
+
+/* this struct is used to translate between ipoib and
+ ethernet mac addresses */
+struct mac_xlation_st {
+ __u8 valid; /* 1=entry valid 0=entry free */
+ __u32 youth; /* youth of this entry the lowest the
+ number the older in age */
+ __u8 eth_mac_lsb[3]; /* three bytes Ethernet MAC
+ LS bytes are constants */
+ union ib_gid_u gid;
+ __u32 qpn;
+ ud_av_t av; /* address vector representing neighbour */
+};
+
+static inline __u16 get_prot_type(void *data)
+{
+ __u8 *ptr = data;
+
+ return be16_to_cpu(*((__u16 *) ptr));
+}
+
+static inline __u8 get_hw_len(void *data)
+{
+ return ((__u8 *) data)[8];
+}
+
+static inline __u8 get_prot_size(void *data)
+{
+ return ((__u8 *) data)[9];
+}
+
+static inline __u16 get_opcode(const void *data)
+{
+ return be16_to_cpu(*((__u16 *) (&(((__u8 *) data)[10]))));
+}
+
+static inline __u32 get_sender_qpn(void *data)
+{
+ __u8 *ptr = data;
+
+ return (ptr[13] << 16) | (ptr[14] << 8) | ptr[15];
+}
+
+static inline const __u8 *get_sender_gid(void *data)
+{
+ return &(((__u8 *) data)[16]);
+}
+
+static inline void *arp_mac6_get_sender_ip(const void *data)
+{
+ return (__u8 *) data + 14;
+}
+
+static inline const void *arp_mac6_get_target_ip(const void *data)
+{
+ return data + 24;
+}
+
+static inline void arp_mac20_set_sender_ip(const void *ip, void *data)
+{
+ memcpy(((__u8 *) data) + 28, ip, 4);
+}
+
+static inline void arp_mac20_set_target_ip(const void *ip, void *data)
+{
+ memcpy(((__u8 *) data) + 52, ip, 4);
+}
+
+static inline void arp_mac20_set_sender_mac(const void *qpn, const void *gid,
+ void *data)
+{
+ memcpy(((__u8 *) data) + 9, qpn, 3);
+ memcpy(((__u8 *) data) + 12, gid, 16);
+}
+
+static inline void arp_mac20_set_target_mac(void *qpn, void *gid, void *data)
+{
+ memcpy(((__u8 *) data) + 33, qpn, 3);
+ memcpy(((__u8 *) data) + 36, gid, 16);
+}
+
+static inline const void *arp_mac6_get_opcode(const void *data)
+{
+ return data + 6;
+}
+
+static inline void arp_mac20_set_opcode(const void *opcode, void *data)
+{
+ memcpy(data + 6, opcode, 2);
+}
+
+static inline const void *arp_mac6_get_target_mac(const void *data)
+{
+ return data + 18;
+}
+
+static inline const void *arp_mac20_get_sender_qpn(void *data)
+{
+ return ((__u8 *) data) + 13;
+}
+
+static inline const void *arp_mac20_get_sender_gid(void *data)
+{
+ return ((__u8 *) data) + 16;
+}
+
+static inline const void *arp_mac20_get_target_qpn(void *data)
+{
+ return ((__u8 *) data) + 37;
+}
+
+static inline const void *arp_mac20_get_target_gid(void *data)
+{
+ return ((__u8 *) data) + 40;
+}
+
+static inline const void *get_lptr_by_off(const void *packet, __u16 offset)
+{
+ return packet + offset;
+}
+
+static inline __u8 get_ip_protocl_type(const void *packet)
+{
+ const void *ptr;
+ __u8 prot;
+
+ ptr = get_lptr_by_off(packet, 9);
+
+ memcpy(&prot, ptr, 1);
+ return prot;
+}
+
+static inline __u16 get_udp_dest_port(const void *packet)
+{
+ const void *ptr;
+ __u16 port;
+
+ ptr = get_lptr_by_off(packet, 22);
+
+ memcpy(&port, ptr, 2);
+ return port;
+}
+
+static inline __u8 get_dhcp_message_type(const void *packet)
+{
+ const void *ptr;
+ __u8 type;
+
+ ptr = get_lptr_by_off(packet, 28);
+
+ memcpy(&type, ptr, 1);
+ return type;
+}
+
+static inline void set_hw_type(__u8 * packet)
+{
+ packet[29] = IPOIB_HW_TYPE;
+}
+
+static inline void zero_hw_len(__u8 * packet)
+{
+ packet[30] = 0;
+}
+
+static inline void set_udp_csum(__u8 * packet, __u16 val)
+{
+ __u16 *csum_ptr;
+
+ csum_ptr = (__u16 *) (packet + 26);
+
+ *csum_ptr = htons(val);
+}
+
+static inline void zero_chaddr(__u8 * packet)
+{
+ memset(packet + 56, 0, 16);
+}
+
+static inline void set_bcast_flag(__u8 * packet)
+{
+ packet[38] = 0x80;
+}
+
+static inline __u8 get_ip_protocl(void *buf)
+{
+ return ((__u8 *) buf)[9];
+}
+
+static inline __u16 get_udp_dst_port(void *buf)
+{
+ return be16_to_cpu(*((__u16 *) (((__u8 *) buf) + 0x16)));
+}
+
+static inline __u8 get_dhcp_msg_type(void *buf)
+{
+ return ((__u8 *) buf)[0x1c];
+}
+
+static inline void set_eth_hwtype(void *buf)
+{
+ ((__u8 *) buf)[0x1d] = ETH_HW_TYPE;
+}
+
+static inline void set_eth_hwlen(void *buf)
+{
+ ((__u8 *) buf)[0x1e] = 6;
+}
+
+static inline void add_udp_len(void *buf, __u16 size_add)
+{
+ __u16 old_len, *len_ptr;
+
+ len_ptr = (__u16 *) (((__u8 *) buf) + 24);
+ old_len = ntohs(*len_ptr);
+ *len_ptr = htons(old_len + size_add);
+}
+
+static inline void set_own_mac(void *buf)
+{
+ ((__u8 *) buf)[0x38] = 0xff; //MLX_ETH_BYTE0;
+ ((__u8 *) buf)[0x39] = 0xff; //MLX_ETH_BYTE1;
+ ((__u8 *) buf)[0x3a] = 0xff; //MLX_ETH_BYTE2;
+ ((__u8 *) buf)[0x3b] = 0xff; //0;
+ ((__u8 *) buf)[0x3c] = 0xff; //0;
+ ((__u8 *) buf)[0x3d] = 0xff; //0;
+}
+
+static int ipoib_handle_rcv(void *buf, void **out_buf_p,
+ unsigned int *new_size_p, int *bcast_p);
+static int ipoib_send_packet(const __u8 * mac, __u16 protocol, const void *data,
+ unsigned int size);
+static int ipoib_init(struct pci_device *pci);
+static u8 *get_port_gid(void);
+static int ipoib_read_packet(__u16 * prot_p, void *data, unsigned int *size_p,
+ int *is_bcast_p);
+
+#endif /* __ipoib_h__ */
diff --git a/src/drivers/net/mlx_ipoib/mad_attrib.h b/src/drivers/net/mlx_ipoib/mad_attrib.h
new file mode 100644
index 000000000..e7af67930
--- /dev/null
+++ b/src/drivers/net/mlx_ipoib/mad_attrib.h
@@ -0,0 +1,244 @@
+/*
+ This software is available to you under a choice of one of two
+ licenses. You may choose to be licensed under the terms of the GNU
+ General Public License (GPL) Version 2, available at
+ <http://www.fsf.org/copyleft/gpl.html>, or the OpenIB.org BSD
+ license, available in the LICENSE.TXT file accompanying this
+ software. These details are also available at
+ <http://openib.org/license.html>.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+
+ Copyright (c) 2004 Mellanox Technologies Ltd. All rights reserved.
+*/
+
+#ifndef __mad_attrib_h_
+#define __mad_attrib_h_
+
+#include "ib_mad.h"
+
+#define IB_SA_ATTR_MC_MEMBER_REC 0x38
+#define IB_SA_ATTR_PATH_REC 0x35
+
+#define IB_SA_MCMEMBER_REC_MGID (1<<0)
+#define IB_SA_MCMEMBER_REC_PORT_GID (1<<1)
+#define IB_SA_MCMEMBER_REC_QKEY (1<<2)
+#define IB_SA_MCMEMBER_REC_MLID (1<<3)
+#define IB_SA_MCMEMBER_REC_MTU_SELECTOR (1<<4)
+#define IB_SA_MCMEMBER_REC_MTU (1<<5)
+#define IB_SA_MCMEMBER_REC_TRAFFIC_CLASS (1<<6)
+#define IB_SA_MCMEMBER_REC_PKEY (1<<7)
+#define IB_SA_MCMEMBER_REC_RATE_SELECTOR (1<<8)
+#define IB_SA_MCMEMBER_REC_RATE (1<<9)
+#define IB_SA_MCMEMBER_REC_PACKET_LIFE_TIME_SELECTOR (1<<10)
+#define IB_SA_MCMEMBER_REC_PACKET_LIFE_TIME (1<<11)
+#define IB_SA_MCMEMBER_REC_SL (1<<12)
+#define IB_SA_MCMEMBER_REC_FLOW_LABEL (1<<13)
+#define IB_SA_MCMEMBER_REC_HOP_LIMIT (1<<14)
+#define IB_SA_MCMEMBER_REC_SCOPE (1<<15)
+#define IB_SA_MCMEMBER_REC_JOIN_STATE (1<<16)
+#define IB_SA_MCMEMBER_REC_PROXY_JOIN (1<<17)
+
+#define IB_SA_PATH_REC_DGID (1<<2)
+#define IB_SA_PATH_REC_SGID (1<<3)
+
+struct port_info_st {
+ __u32 mkey[2];
+ __u32 gid_prefix[2];
+ __u16 mastersm_lid;
+ __u16 lid;
+ __u32 cap_mask;
+ __u32 combined2;
+ /*__u32 mkey_lease_period:16;
+ __u32 diag_code:16;*/
+ __u32 combined3;
+ /*__u32 link_width_active:8;
+ __u32 link_width_supported:8;
+ __u32 link_width_enabled:8;
+ __u32 local_port_num:8;*/
+ __u32 combined4;
+ /*__u32 link_speed_enabled:4;
+ __u32 link_speed_active:4;
+ __u32 lmc:3;
+ __u32 r1:3;
+ __u32 mkey_prot_bits:2;
+ __u32 link_down_def_state:4;
+ __u32 port_phys_state:4;
+ __u32 port_state:4;
+ __u32 link_speed_supported:4;*/
+ __u32 combined5;
+ /*__u32 vl_arb_hi_cap:8;
+ __u32 vl_hi_limit:8;
+ __u32 init_type:4;
+ __u32 vl_cap:4;
+ __u32 master_smsl:4;
+ __u32 neigh_mtu:4;*/
+ __u32 combined6;
+ /*__u32 filt_raw_oub:1;
+ __u32 filt_raw_inb:1;
+ __u32 part_enf_oub:1;
+ __u32 part_enf_inb:1;
+ __u32 op_vls:4;
+ __u32 hoq_life:5;
+ __u32 vl_stall_count:3;
+ __u32 mtu_cap:4;
+ __u32 init_type_reply:4;
+ __u32 vl_arb_lo_cap:8;*/
+ __u32 combined7;
+ /*__u32 pkey_viol:16;
+ __u32 mkey_viol:16;*/
+ __u32 combined8;
+ /*__u32 subn_tout:5;
+ __u32 r2:2;
+ __u32 client_rereg:1;
+ __u32 guid_cap:8;
+ __u32 qkey_viol:16;*/
+ __u32 combined9;
+ /*__u32 max_cred_hint:16;
+ __u32 overrun_err:4;
+ __u32 local_phy_err:4;
+ __u32 resp_t_val:5;
+ __u32 r3:3;*/
+ __u32 combined10;
+ /*__u32 r4:8;
+ __u32 link_rtrip_lat:24;*/
+} __attribute__ ((packed));
+
+struct port_info_mad_st {
+ struct ib_mad_hdr_st mad_hdr;
+ __u32 mkey[2];
+ __u32 r1[8];
+ struct port_info_st port_info;
+} __attribute__ ((packed));
+
+union port_info_mad_u {
+ __u8 raw[256];
+ struct port_info_mad_st mad;
+} __attribute__ ((packed));
+
+struct guid_info_st {
+ union ib_gid_u gid_tbl[8];
+} __attribute__ ((packed));
+
+struct guid_info_mad_st {
+ struct ib_mad_hdr_st mad_hdr;
+ __u32 mkey[2];
+ __u32 r1[8];
+ struct guid_info_st guid_info;
+} __attribute__ ((packed));
+
+union guid_info_mad_u {
+ __u8 raw[256];
+ struct guid_info_mad_st mad;
+} __attribute__ ((packed));
+
+struct mc_member_st {
+ __u8 mgid[16];
+ __u8 port_gid[16];
+ __u32 q_key;
+ __u32 combined1;
+ /*__u32 tclass:8;
+ __u32 mtu:6;
+ __u32 mtu_selector:2;
+ __u32 mlid:16;*/
+ __u32 combined2;
+ /*__u32 packet_liftime:6;
+ __u32 packet_liftime_selector:2;
+ __u32 rate:6;
+ __u32 rate_selector:2;
+ __u32 pkey:16;*/
+ __u32 combined3;
+ /*__u32 hop_limit:8;
+ __u32 flow_label:20;
+ __u32 sl:4;*/
+ __u32 combined4;
+ /*__u32 r0:23;
+ __u32 proxy_join:1;
+ __u32 join_state:4;
+ __u32 scope:4;*/
+} __attribute__ ((packed));
+
+struct mc_member_mad_st {
+ struct ib_mad_hdr_st mad_hdr;
+ struct rmpp_hdr_st rmpp_hdr;
+ struct sa_header_st sa_hdr;
+ struct mc_member_st mc_member;
+} __attribute__ ((packed));
+
+union mc_member_mad_u {
+ struct mc_member_mad_st mc_member;
+ __u8 raw[256];
+} __attribute__ ((packed));
+
+struct pkey_tbl_st {
+ __u16 pkey_tbl[16][2];
+} __attribute__ ((packed));
+
+struct pkey_tbl_mad_st {
+ struct ib_mad_hdr_st mad_hdr;
+ __u32 mkey[2];
+ __u32 r1[8];
+ struct pkey_tbl_st pkey_tbl;
+} __attribute__ ((packed));
+
+union pkey_tbl_mad_u {
+ struct pkey_tbl_mad_st mad;
+ __u8 raw[256];
+} __attribute__ ((packed));
+
+struct path_record_st {
+ __u32 r0[2];
+ union ib_gid_u dgid;
+ union ib_gid_u sgid;
+ __u16 slid;
+ __u16 dlid;
+ __u32 combined1;
+ /*__u32 hop_limit:8;
+ __u32 flow_label:20;
+ __u32 r1:3;
+ __u32 raw_traffic:1;*/
+ __u32 combined2;
+ /*__u32 pkey:16;
+ __u32 numb_path:7;
+ __u32 reversible:1;
+ __u32 tclass:8;*/
+ __u32 combined3;
+ /*__u32 rate:6;
+ __u32 rate_selector:2;
+ __u32 mtu:6;
+ __u32 mtu_selector:2;
+ __u32 sl:4;
+ __u32 reserved:12;*/
+ __u32 combined4;
+ /*__u32 r2:16;
+ __u32 preference:8;
+ __u32 packet_lifetime:6;
+ __u32 packet_lifetime_selector:2;*/
+ __u32 r3;
+} __attribute__ ((packed));
+
+struct path_record_mad_st {
+ struct ib_mad_hdr_st mad_hdr;
+ struct rmpp_hdr_st rmpp_hdr;
+ struct sa_header_st sa_hdr;
+ struct path_record_st path_record;
+} __attribute__ ((packed));
+
+union path_record_mad_u {
+ struct path_record_mad_st mad;
+ __u8 raw[256];
+} __attribute__ ((packed));
+
+static int get_port_info(__u8 port, struct port_info_st *buf, __u16 * status);
+static int get_guid_info(__u16 * status);
+static int get_pkey_tbl(struct pkey_tbl_st *pkey_tbl, __u16 * status);
+static int join_mc_group(__u32 * qkey_p, __u16 * mlid_p, __u8 join);
+
+#endif /* __mad_attrib_h_ */
diff --git a/src/drivers/net/mlx_ipoib/mt23108.c b/src/drivers/net/mlx_ipoib/mt23108.c
new file mode 100644
index 000000000..157995d75
--- /dev/null
+++ b/src/drivers/net/mlx_ipoib/mt23108.c
@@ -0,0 +1,245 @@
+/**************************************************************************
+Etherboot - BOOTP/TFTP Bootstrap Program
+Skeleton NIC driver for Etherboot
+***************************************************************************/
+
+/*
+ * 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, or (at
+ * your option) any later version.
+ */
+
+/* to get some global routines like printf */
+#include "etherboot.h"
+/* to get the interface to the body of the program */
+#include "nic.h"
+/* to get the PCI support functions, if this is a PCI NIC */
+#include "pci.h"
+/* to get the ISA support functions, if this is an ISA NIC */
+#include "isa.h"
+
+#include "mt_version.c"
+#include "mt23108_imp.c"
+
+/* NIC specific static variables go here */
+
+int prompt_key(int secs, unsigned char *ch_p)
+{
+ unsigned long tmo;
+ unsigned char ch;
+
+ for (tmo = currticks() + secs * TICKS_PER_SEC; currticks() < tmo;) {
+ if (iskey()) {
+ ch = getchar();
+ /* toupper does not work ... */
+ if (ch == 'v')
+ ch = 'V';
+ if (ch == 'i')
+ ch = 'I';
+ if ((ch=='V') || (ch=='I')) {
+ *ch_p = ch;
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+/**************************************************************************
+IRQ - handle interrupts
+***************************************************************************/
+static void tavor_irq(struct nic *nic, irq_action_t action)
+{
+ /* This routine is somewhat optional. Etherboot itself
+ * doesn't use interrupts, but they are required under some
+ * circumstances when we're acting as a PXE stack.
+ *
+ * If you don't implement this routine, the only effect will
+ * be that your driver cannot be used via Etherboot's UNDI
+ * API. This won't affect programs that use only the UDP
+ * portion of the PXE API, such as pxelinux.
+ */
+
+ if (0) {
+ nic = NULL;
+ }
+ switch (action) {
+ case DISABLE:
+ case ENABLE:
+ /* Set receive interrupt enabled/disabled state */
+ /*
+ outb ( action == ENABLE ? IntrMaskEnabled : IntrMaskDisabled,
+ nic->ioaddr + IntrMaskRegister );
+ */
+ break;
+ case FORCE:
+ /* Force NIC to generate a receive interrupt */
+ /*
+ outb ( ForceInterrupt, nic->ioaddr + IntrForceRegister );
+ */
+ break;
+ }
+}
+
+/**************************************************************************
+POLL - Wait for a frame
+***************************************************************************/
+static int tavor_poll(struct nic *nic, int retrieve)
+{
+ /* Work out whether or not there's an ethernet packet ready to
+ * read. Return 0 if not.
+ */
+ /*
+ if ( ! <packet_ready> ) return 0;
+ */
+
+ /* retrieve==0 indicates that we are just checking for the
+ * presence of a packet but don't want to read it just yet.
+ */
+ /*
+ if ( ! retrieve ) return 1;
+ */
+
+ /* Copy data to nic->packet. Data should include the
+ * link-layer header (dest MAC, source MAC, type).
+ * Store length of data in nic->packetlen.
+ * Return true to indicate a packet has been read.
+ */
+ /*
+ nic->packetlen = <packet_length>;
+ memcpy ( nic->packet, <packet_data>, <packet_length> );
+ return 1;
+ */
+ unsigned int size;
+ int rc;
+ rc = poll_imp(nic, retrieve, &size);
+ if (rc) {
+ return 0;
+ }
+
+ if (size == 0) {
+ return 0;
+ }
+
+ nic->packetlen = size;
+
+ return 1;
+}
+
+/**************************************************************************
+TRANSMIT - Transmit a frame
+***************************************************************************/
+static void tavor_transmit(struct nic *nic, const char *dest, /* Destination */
+ unsigned int type, /* Type */
+ unsigned int size, /* size */
+ const char *packet)
+{ /* Packet */
+ int rc;
+
+ /* Transmit packet to dest MAC address. You will need to
+ * construct the link-layer header (dest MAC, source MAC,
+ * type).
+ */
+ if (nic) {
+ rc = transmit_imp(dest, type, packet, size);
+ if (rc)
+ eprintf("tranmit error");
+ }
+}
+
+/**************************************************************************
+DISABLE - Turn off ethernet interface
+***************************************************************************/
+static void tavor_disable(struct dev *dev)
+{
+ /* put the card in its initial state */
+ /* This function serves 3 purposes.
+ * This disables DMA and interrupts so we don't receive
+ * unexpected packets or interrupts from the card after
+ * etherboot has finished.
+ * This frees resources so etherboot may use
+ * this driver on another interface
+ * This allows etherboot to reinitialize the interface
+ * if something is something goes wrong.
+ */
+ if (dev || 1) { // ????
+ disable_imp();
+ }
+}
+
+/**************************************************************************
+PROBE - Look for an adapter, this routine's visible to the outside
+***************************************************************************/
+
+static int tavor_probe(struct dev *dev, struct pci_device *pci)
+{
+ struct nic *nic = (struct nic *)dev;
+ int rc;
+ unsigned char user_request;
+
+ if (pci->vendor != MELLANOX_VENDOR_ID) {
+ eprintf("");
+ return 0;
+ }
+
+ printf("\n");
+ printf("Mellanox Technologies LTD - Boot over IB implementaion\n");
+ printf("Build version = %s\n\n", build_revision);
+
+ verbose_messages = 0;
+ print_info = 0;
+ printf("Press within 3 seconds:\n");
+ printf("V - to increase verbosity\n");
+ printf("I - to print information\n");
+ if (prompt_key(3, &user_request)) {
+ if (user_request == 'V') {
+ printf("User selected verbose messages\n");
+ verbose_messages = 1;
+ }
+ else if (user_request == 'I') {
+ printf("User selected to print information\n");
+ print_info = 1;
+ }
+ }
+ printf("\n");
+
+ adjust_pci_device(pci);
+
+ nic->priv_data = NULL;
+ rc = probe_imp(pci, nic);
+
+ /* give the user a chance to look at the info */
+ if (print_info)
+ sleep(5);
+
+ if (!rc) {
+ /* store NIC parameters */
+ nic->ioaddr = pci->ioaddr & ~3;
+ nic->irqno = pci->irq;
+ /* point to NIC specific routines */
+ dev->disable = tavor_disable;
+ nic->poll = tavor_poll;
+ nic->transmit = tavor_transmit;
+ nic->irq = tavor_irq;
+
+ return 1;
+ }
+ /* else */
+ return 0;
+}
+
+static struct pci_id tavor_nics[] = {
+ PCI_ROM(0x15b3, 0x5a44, "MT23108", "MT23108 HCA driver"),
+ PCI_ROM(0x15b3, 0x6278, "MT25208", "MT25208 HCA driver"),
+};
+
+static struct pci_driver tavor_driver __pci_driver = {
+ .type = NIC_DRIVER,
+ .name = "MT23108/MT25208",
+ .probe = tavor_probe,
+ .ids = tavor_nics,
+ .id_count = sizeof(tavor_nics) / sizeof(tavor_nics[0]),
+ .class = 0,
+};
diff --git a/src/drivers/net/mlx_ipoib/mt23108.h b/src/drivers/net/mlx_ipoib/mt23108.h
new file mode 100644
index 000000000..1e144ee42
--- /dev/null
+++ b/src/drivers/net/mlx_ipoib/mt23108.h
@@ -0,0 +1,543 @@
+#ifndef __mt23108_h__
+#define __mt23108_h__
+
+#include "MT23108_PRM.h"
+#include "ib_mad.h"
+
+#define TAVOR_DEVICE_ID 0x5a44
+#define TAVOR_BRIDGE_DEVICE_ID 0x5a46
+#define ARTAVOR_DEVICE_ID 0x6278
+
+#define TAVOR_RESET_OFFSET 0xF0010
+
+/*
+ * Tavor specific command
+ * Only coomands that are specific to Tavor
+ * and used by the driver are listed here
+ */
+#define TAVOR_CMD_SYS_EN 0x1
+#define TAVOR_CMD_SYS_DIS 0x2
+
+#define TAVOR_CMD_WRITE_MGM 0x26
+#define TAVOR_CMD_MOD_STAT_CFG 0x34
+#define TAVOR_CMD_QUERY_DEV_LIM 0x003
+#define TAVOR_CMD_QUERY_FW 0x004
+
+/*
+ * Tavor specific event types
+ * Only event types that are specific to Tavor
+ * and are used by the driver are listed here
+ */
+#define TAVOR_IF_EV_TYPE_OVERRUN 0x0F
+
+/*
+ * EQ doorbel commands
+ */
+#define EQ_DBELL_CMD_INC_CONS_IDX 1 /* increment Consumer_indx by one */
+#define EQ_DBELL_CMD_ARM_EQ 2 /* Request notifcation for next event (Arm EQ) */
+#define EQ_DBELL_CMD_DISARM_CQ 3 /* Disarm CQ (CQ number is specified in EQ_param) */
+#define EQ_DBELL_CMD_SET_CONS_IDX 4 /* set Consumer_indx to value of EQ_param */
+#define EQ_DBELL_CMD_ALWAYS_ARM 5 /* move EQ to Always Armed state */
+
+/*
+ * CQ doorbel commands
+ */
+#define CQ_DBELL_CMD_INC_CONS_IDX 1
+#define CQ_DBELL_CMD_REQ_NOTIF_SOL_UNSOL 2
+#define CQ_DBELL_CMD_REQ_NOTIF_SOL 3
+#define CQ_DBELL_CMD_SET_CONS_IDX 4
+#define CQ_DBELL_CMD_REQ_NOTIF_MULT 5
+
+#define INPRM_BUF_SZ 0x200
+#define INPRM_BUF_ALIGN 16
+#define OUTPRM_BUF_SZ 0x200
+#define OUTPRM_BUF_ALIGN 16
+
+/*
+ * sizes of parameter blocks used in certain
+ * commands.
+ * TODO: replace them with sizeof
+ * operators of the appropriate structs
+ */
+#define SW2HW_MPT_IBUF_SZ MT_STRUCT_SIZE(tavorprm_mpt_st)
+#define SW2HW_EQ_IBUF_SZ MT_STRUCT_SIZE(tavorprm_eqc_st)
+#define INIT_IB_IBUF_SZ 0x100
+#define SW2HW_CQ_IBUF_SZ 0x40
+#define QPCTX_IBUF_SZ 0x200
+
+#define EQN 0
+#define UAR_IDX 1
+
+#define QPC_OFFSET 0
+#define CQC_OFFSET (QPC_OFFSET + 0x100000)
+#define EQPC_OFFSET (CQC_OFFSET + 0x100000)
+#define EQC_OFFSET (EQPC_OFFSET + 0x100000)
+#define MC_BASE_OFFSET (EQC_OFFSET + 0x100000)
+#define MPT_BASE_OFFSET (MC_BASE_OFFSET + 0x100000)
+#define MTT_BASE_OFFSET (MPT_BASE_OFFSET + 0x100000)
+
+#define LOG2_QPS 7
+#define LOG2_CQS 8
+#define LOG2_EQS 6
+#define LOG2_MC_ENTRY 6 /* 8 QPs per group */
+#define LOG2_MC_GROUPS 3 /* 8 groups */
+#define LOG2_MPT_ENTRIES 5
+
+#define LOG2_EQ_SZ 5
+#define LOG2_CQ_SZ 5
+
+#define NUM_PORTS 2
+
+#define EQE_OWNER_SW 0
+#define EQE_OWNER_HW 1
+
+#define OWNER_HW 1
+#define OWNER_SW 0
+
+#define POST_RCV_OFFSET 0x18
+#define POST_SND_OFFSET 0x10
+#define CQ_DBELL_OFFSET 0x20
+#define EQ_DBELL_OFFSET 0x28
+
+#define CQE_ERROR_OPCODE 0xfe
+
+#define MAX_GATHER 1 /* max gather entries used in send */
+#define MAX_SCATTER 2
+
+#define LOG2_MADS_SND_CQ_SZ LOG2_CQ_SZ
+#define LOG2_MADS_RCV_CQ_SZ LOG2_CQ_SZ
+#define LOG2_IPOIB_SND_CQ_SZ LOG2_CQ_SZ
+#define LOG2_IPOIB_RCV_CQ_SZ LOG2_CQ_SZ
+
+#define NUM_MADS_SND_CQES (1<<LOG2_MADS_SND_CQ_SZ)
+#define NUM_MADS_RCV_CQES (1<<LOG2_MADS_RCV_CQ_SZ)
+#define NUM_IPOIB_SND_CQES (1<<LOG2_IPOIB_SND_CQ_SZ)
+#define NUM_IPOIB_RCV_CQES (1<<LOG2_IPOIB_RCV_CQ_SZ)
+
+#define NUM_MADS_RCV_WQES 3
+#define NUM_IPOIB_RCV_WQES 8
+
+#if NUM_MADS_RCV_WQES > NUM_IPOIB_RCV_WQES
+#define MAX_RCV_WQES NUM_MADS_RCV_WQES
+#else
+#define MAX_RCV_WQES NUM_IPOIB_RCV_WQES
+#endif
+
+#define NUM_MADS_SND_WQES 2
+#define NUM_IPOIB_SND_WQES 2
+
+#if NUM_MADS_SND_WQES > NUM_IPOIB_SND_WQES
+#define MAX_SND_WQES NUM_MADS_SND_WQES
+#else
+#define MAX_SND_WQES NUM_IPOIB_SND_WQES
+#endif
+
+struct ib_buffers_st {
+ __u8 send_mad_buf[NUM_MADS_SND_WQES][MAD_BUF_SZ];
+ __u8 rcv_mad_buf[NUM_MADS_RCV_WQES][MAD_BUF_SZ + GRH_SIZE];
+ __u8 ipoib_rcv_buf[NUM_IPOIB_RCV_WQES][IPOIB_RCV_BUF_SZ + GRH_SIZE];
+ __u8 ipoib_rcv_grh_buf[NUM_IPOIB_RCV_WQES][IPOIB_RCV_BUF_SZ];
+ __u8 send_ipoib_buf[NUM_IPOIB_SND_WQES][IPOIB_SND_BUF_SZ];
+};
+
+struct pcidev {
+ unsigned long bar[6];
+ __u32 dev_config_space[64];
+ struct pci_device *dev;
+ __u8 bus;
+ __u8 devfn;
+};
+
+struct dev_pci_struct {
+ struct pcidev dev;
+ struct pcidev br;
+ void *cr_space;
+ void *uar;
+};
+
+struct eq_st {
+ __u8 eqn;
+ __u32 cons_idx;
+ __u32 eq_size;
+ struct eqe_t *eq_buf;
+};
+
+struct udav_st {
+ union ud_av_u *av_array;
+ __u8 udav_next_free;
+};
+
+#if 0
+struct udavtable_memory_parameters_st {
+ __u32 lkey;
+ __u32 pd:24;
+ __u32 r0:5;
+ __u32 xlation_en:1;
+ __u32 r1:2;
+} __attribute__ ((packed));
+
+struct multicast_parameters_st {
+ __u32 mc_base_addr_h;
+ __u32 mc_base_addr_l;
+ __u32 r0[2];
+ __u32 log_mc_table_entry_sz:16;
+ __u32 r1:16;
+ __u32 mc_table_hash_sz:17;
+ __u32 r2:15;
+ __u32 log_mc_table_sz:5;
+ __u32 r3:19;
+ __u32 mc_hash_fn:3;
+ __u32 r4:5;
+ __u32 r5;
+} __attribute__ ((packed));
+
+struct tpt_parameters_st {
+ __u32 mpt_base_addr_h;
+ __u32 mpt_base_addr_l;
+
+ __u32 log_mpt_sz:6;
+ __u32 r0:2;
+ __u32 pfto:5;
+ __u32 r1:3;
+ __u32 mtt_segment_size:3;
+ __u32 r2:13;
+
+ __u32 mtt_version:8;
+ __u32 r3:24;
+
+ __u32 mtt_base_addr_h;
+ __u32 mtt_base_addr_l;
+ __u32 r4[2];
+} __attribute__ ((packed));
+
+struct uar_parameters_st {
+ __u32 uar_base_addr_h;
+ __u32 uar_base_addr_l; /* 12 lsbs must be zero */
+ __u32 uar_page_sz:8;
+ __u32 r1:24;
+ __u32 r2;
+ __u32 uar_scratch_base_addr_h;
+ __u32 uar_scratch_base_addr_l;
+ __u32 r3[3];
+} __attribute__ ((packed));
+
+struct comp_event_data_st {
+ __u32 cqn:24;
+ __u32 r1:8;
+ __u32 r2[5];
+} __attribute__ ((packed));
+
+struct qp_event_data_st {
+ __u32 qpn_een:24;
+ __u32 r1:8;
+ __u32 r2;
+ __u32 r3:28;
+ __u32 e_q:1;
+ __u32 r4:3;
+ __u32 r5[3];
+} __attribute__ ((packed));
+
+struct port_state_change_event_data_st {
+ __u32 r0[2];
+ __u32 r1:28;
+ __u32 port:2;
+ __u32 r2:2;
+ __u32 r3[3];
+} __attribute__ ((packed));
+#endif
+
+struct eqe_t {
+ __u8 raw[MT_STRUCT_SIZE(tavorprm_event_queue_entry_st)];
+} __attribute__ ((packed));
+
+enum qp_state_e {
+ QP_STATE_RST = 0,
+ QP_STATE_INIT = 1,
+ QP_STATE_RTR = 2,
+ QP_STATE_RTS = 3,
+ QP_STATE_SQEr = 4,
+ QP_STATE_SQD = 5,
+ QP_STATE_ERR = 6,
+ QP_STATE_SQDING = 7,
+ QP_STATE_SUSPEND = 9
+};
+
+struct memory_pointer_st {
+ __u32 byte_count;
+ __u32 lkey;
+ __u32 local_addr_h;
+ __u32 local_addr_l;
+} __attribute__ ((packed));
+
+/* receive wqe descriptor */
+struct recv_wqe_st {
+ /* part referenced by hardware */
+ __u8 next[MT_STRUCT_SIZE(wqe_segment_next_st)];
+ __u8 control[MT_STRUCT_SIZE(wqe_segment_ctrl_recv_st)];
+ struct memory_pointer_st mpointer[MAX_SCATTER];
+} __attribute__ ((packed));
+
+struct recv_wqe_cont_st {
+ struct recv_wqe_st wqe;
+
+ struct udqp_st *qp; /* qp this wqe is used with */
+} __attribute__ ((packed));
+
+#define RECV_WQE_U_ALIGN 64
+union recv_wqe_u {
+ __u8 align[(sizeof(struct recv_wqe_cont_st) + RECV_WQE_U_ALIGN - 1) & (~(RECV_WQE_U_ALIGN - 1))]; /* this ensures proper alignment */
+ struct recv_wqe_st wqe;
+ struct recv_wqe_cont_st wqe_cont;
+} __attribute__ ((packed));
+
+struct recv_doorbell_st {
+ __u8 raw[MT_STRUCT_SIZE(tavorprm_receive_doorbell_st)];
+} __attribute__ ((packed));
+
+struct send_doorbell_st {
+ __u8 raw[MT_STRUCT_SIZE(tavorprm_send_doorbell_st)];
+} __attribute__ ((packed));
+
+struct next_control_seg_st {
+ __u8 next[MT_STRUCT_SIZE(wqe_segment_next_st)];
+ __u8 control[MT_STRUCT_SIZE(wqe_segment_ctrl_send_st)];
+} __attribute__ ((packed));
+
+struct ud_seg_st {
+ __u32 r1;
+ __u32 lkey;
+ __u32 av_add_h;
+ __u32 av_add_l;
+ __u32 r2[4];
+ __u32 dest_qp;
+ __u32 qkey;
+ __u32 r3[2];
+} __attribute__ ((packed));
+
+struct ud_send_wqe_st {
+ struct next_control_seg_st next;
+ struct ud_seg_st udseg;
+ struct memory_pointer_st mpointer[MAX_GATHER];
+} __attribute__ ((packed));
+
+struct ude_send_wqe_cont_st {
+ struct ud_send_wqe_st wqe;
+
+ struct udqp_st *qp; /* qp this wqe is used with */
+} __attribute__ ((packed));
+
+#define UD_SEND_WQE_U_ALIGN 64
+union ud_send_wqe_u {
+ __u8 align[(sizeof(struct ude_send_wqe_cont_st) + UD_SEND_WQE_U_ALIGN -
+ 1) & (~(UD_SEND_WQE_U_ALIGN - 1))];
+ struct ude_send_wqe_cont_st wqe_cont;
+ struct ud_send_wqe_st wqe;
+} __attribute__ ((packed));
+
+#define ADDRESS_VECTOR_ST_ALIGN 64
+struct address_vector_st {
+ __u8 raw[MT_STRUCT_SIZE(tavorprm_ud_address_vector_st)];
+} __attribute__ ((packed));
+
+struct ud_av_st {
+ struct address_vector_st av;
+ __u32 dest_qp; /* destination qpn */
+ __u8 next_free;
+} __attribute__ ((packed));
+
+union ud_av_u {
+ __u8 raw[(sizeof(struct ud_av_st) + ADDRESS_VECTOR_ST_ALIGN -
+ 1) & (~(ADDRESS_VECTOR_ST_ALIGN - 1))];
+ struct ud_av_st ud_av;
+} __attribute__ ((packed));
+
+union cqe_st {
+ __u8 good_cqe[MT_STRUCT_SIZE(tavorprm_completion_queue_entry_st)];
+ __u8 error_cqe[MT_STRUCT_SIZE(tavorprm_completion_with_error_st)];
+} __attribute__ ((packed));
+
+struct address_path_st {
+ __u8 raw[MT_STRUCT_SIZE(tavorprm_address_path_st)];
+};
+
+struct qp_ee_ctx_t {
+ __u8 raw[MT_STRUCT_SIZE(tavorprm_queue_pair_ee_context_entry_st)];
+} __attribute__ ((packed));
+
+struct qp_ee_state_tarnisition_st {
+ __u32 opt_param_mask;
+ __u32 r1;
+ struct qp_ee_ctx_t ctx;
+ __u32 r2[62];
+} __attribute__ ((packed));
+
+struct eq_dbell_st {
+ __u8 raw[MT_STRUCT_SIZE(tavorprm_eq_cmd_doorbell_st)];
+} __attribute__ ((packed));
+
+struct cq_dbell_st {
+ __u8 raw[MT_STRUCT_SIZE(tavorprm_cq_cmd_doorbell_st)];
+} __attribute__ ((packed));
+
+struct mad_ifc_inprm_st {
+ union mad_u mad;
+} __attribute__ ((packed));
+
+struct wqe_buf_st {
+ struct ud_send_wqe_st *sndq;
+ struct recv_wqe_st *rcvq;
+};
+
+struct mad_buffer_st {
+ void *buf; /* pointer to a 256 byte buffer */
+ __u8 owner; /* sw or hw ownership BUF_OWNER_SW or BUF_OWNER_HW */
+};
+
+struct rcv_buf_st {
+ void *buf;
+ __u8 busy;
+};
+
+struct ib_eqe_st {
+ __u8 event_type;
+ __u32 cqn;
+};
+
+struct cq_st {
+ __u32 cqn;
+ union cqe_st *cq_buf;
+ __u32 cons_idx;
+ __u8 num_cqes;
+};
+
+struct udqp_st {
+ /* cq used by this QP */
+ struct cq_st snd_cq;
+ struct cq_st rcv_cq;
+
+ /* QP related data */
+ __u32 qpn; /* QP number */
+
+ __u32 qkey;
+
+ __u8 recv_wqe_cur_free;
+ __u8 recv_wqe_alloc_idx;
+ __u8 max_recv_wqes;
+ void *rcv_bufs[MAX_RCV_WQES];
+ union recv_wqe_u *rcv_wq; /* receive work queue */
+ struct recv_wqe_st *last_posted_rcv_wqe;
+
+ __u8 snd_wqe_cur_free;
+ __u8 snd_wqe_alloc_idx;
+ __u8 max_snd_wqes;
+ void *snd_bufs[MAX_SND_WQES];
+ __u16 send_buf_sz;
+ __u16 rcv_buf_sz;
+ union ud_send_wqe_u *snd_wq; /* send work queue */
+ struct ud_send_wqe_st *last_posted_snd_wqe;
+};
+
+struct device_ib_data_st {
+ __u32 mkey;
+ __u32 pd;
+ __u8 port;
+ __u32 qkey;
+ struct eq_st eq;
+ struct udav_st udav;
+ struct udqp_st mads_qp;
+ struct udqp_st ipoib_qp;
+ void *error_buf_addr;
+ __u32 error_buf_size;
+};
+
+
+
+struct query_fw_st {
+ __u16 fw_rev_major;
+ __u16 fw_rev_minor;
+ __u16 fw_rev_subminor;
+ __u32 error_buf_start_h;
+ __u32 error_buf_start_l;
+ __u32 error_buf_size;
+};
+
+
+struct dev_lim_st {
+ __u8 log2_rsvd_qps;
+ __u16 qpc_entry_sz;
+
+ __u8 log2_rsvd_srqs;
+ __u16 srq_entry_sz;
+
+ __u8 log2_rsvd_ees;
+ __u16 eec_entry_sz;
+
+ __u8 log2_rsvd_cqs;
+ __u16 cqc_entry_sz;
+
+ __u8 log2_rsvd_mtts;
+ __u16 mtt_entry_sz;
+
+ __u8 log2_rsvd_mrws;
+ __u16 mpt_entry_sz;
+
+ __u16 eqc_entry_sz;
+};
+
+struct init_hca_st {
+ __u32 qpc_base_addr_h;
+ __u32 qpc_base_addr_l;
+ __u8 log_num_of_qp;
+
+ __u32 eec_base_addr_h;
+ __u32 eec_base_addr_l;
+ __u8 log_num_of_ee;
+
+ __u32 srqc_base_addr_h;
+ __u32 srqc_base_addr_l;
+ __u8 log_num_of_srq;
+
+ __u32 cqc_base_addr_h;
+ __u32 cqc_base_addr_l;
+ __u8 log_num_of_cq;
+
+ __u32 eqpc_base_addr_h;
+ __u32 eqpc_base_addr_l;
+
+ __u32 eeec_base_addr_h;
+ __u32 eeec_base_addr_l;
+
+ __u32 eqc_base_addr_h;
+ __u32 eqc_base_addr_l;
+ __u8 log_num_of_eq;
+
+ __u32 rdb_base_addr_h;
+ __u32 rdb_base_addr_l;
+
+ __u32 mc_base_addr_h;
+ __u32 mc_base_addr_l;
+ __u16 log_mc_table_entry_sz;
+ __u32 mc_table_hash_sz;
+ __u8 log_mc_table_sz;
+
+ __u32 mpt_base_addr_h;
+ __u32 mpt_base_addr_l;
+ __u8 log_mpt_sz;
+ __u32 mtt_base_addr_h;
+ __u32 mtt_base_addr_l;
+ __u8 log_max_uars;
+};
+
+static int create_udqp(struct udqp_st *qp);
+static int destroy_udqp(struct udqp_st *qp);
+static void *get_send_wqe_buf(void *wqe, __u8 index);
+static void *get_rcv_wqe_buf(void *wqe, __u8 index);
+
+static struct recv_wqe_st *alloc_rcv_wqe(struct udqp_st *qp);
+static int free_wqe(void *wqe);
+static int poll_cq(void *cqh, union cqe_st *cqe_p, __u8 * num_cqes);
+static int poll_eq(struct ib_eqe_st *ib_eqe_p, __u8 * num_eqes);
+static int post_rcv_buf(struct udqp_st *qp, struct recv_wqe_st *rcv_wqe);
+static __u32 dev_get_qpn(void *qph);
+
+#endif /* __mt23108_h__ */
diff --git a/src/drivers/net/mlx_ipoib/mt23108_imp.c b/src/drivers/net/mlx_ipoib/mt23108_imp.c
new file mode 100644
index 000000000..4e601668c
--- /dev/null
+++ b/src/drivers/net/mlx_ipoib/mt23108_imp.c
@@ -0,0 +1,230 @@
+typedef uint32_t __u32;
+typedef uint16_t __u16;
+typedef uint8_t __u8;
+
+static int verbose_messages=0;
+static int print_info=0;
+static int fatal_condition=0;
+static int fw_fatal;
+
+#define tprintf(fmt, a...) \
+ do { \
+ if ( verbose_messages ) { \
+ printf("%s:%d: " fmt "\n", __func__, __LINE__, ##a); \
+ } \
+ } \
+ while(0)
+
+#define eprintf(fmt, a...) \
+ printf("%s:%d: " fmt "\n", __func__, __LINE__, ##a)
+
+static void cpu_to_be_buf(void *buf, int size)
+{
+ int dw_sz = size >> 2, i;
+
+ for (i = 0; i < dw_sz; ++i) {
+ ((__u32 *) buf)[i] = cpu_to_be32(((__u32 *) buf)[i]);
+ }
+}
+
+static void be_to_cpu_buf(void *buf, int size)
+{
+ int dw_sz = size >> 2, i;
+ u32 *p = buf;
+
+ for (i = 0; i < dw_sz; ++i) {
+ p[i] = be32_to_cpu(p[i]);
+ }
+}
+
+#include "timer.h"
+#include "cmdif_mt23108.c"
+#include "cmdif_comm.c"
+#include "ib_mt23108.c"
+#include "ib_mad.c"
+#include "ib_driver.c"
+#include "ipoib.c"
+
+static int probe_imp(struct pci_device *pci, struct nic *nic)
+{
+ int rc;
+
+ if (0 && nic) { /* just to supress warning */
+ return 0;
+ }
+
+ fatal_condition= 0;
+ fw_fatal= 0;
+
+ tprintf("");
+ rc = ipoib_init(pci);
+ if (rc)
+ return rc;
+
+ tprintf("");
+
+ return rc;
+}
+
+static int disable_imp(void)
+{
+ int rc;
+
+ rc = ipoib_close(fw_fatal);
+
+ return rc;
+}
+
+static int transmit_imp(const char *dest, /* Destination */
+ unsigned int type, /* Type */
+ const char *packet, /* Packet */
+ unsigned int size)
+{ /* size */
+ int rc;
+
+ if (fatal_condition) {
+ /* since the transmit function does not return a value
+ we return success but do nothing to suppress error messages */
+ return 0;
+ }
+
+ rc = ipoib_send_packet(dest, type, packet, size);
+ if (rc) {
+ printf("*** ERROR IN SEND FLOW ***\n");
+ printf("restarting Etherboot\n");
+ sleep(1);
+ longjmp(restart_etherboot, -1);
+ /* we should not be here ... */
+ return -1;
+ }
+
+ return rc;
+}
+
+static void hd(void *where, int n)
+{
+ int i;
+
+ while (n > 0) {
+ printf("%X ", where);
+ for (i = 0; i < ((n > 16) ? 16 : n); i++)
+ printf(" %hhX", ((char *)where)[i]);
+ printf("\n");
+ n -= 16;
+ where += 16;
+ }
+}
+
+static int poll_imp(struct nic *nic, int retrieve, unsigned int *size_p)
+{
+ static char packet[2048];
+ static char *last_packet_p = NULL;
+ static unsigned long last_packet_size;
+ char *packet_p;
+ const int eth_header_len = 14;
+ unsigned int packet_len;
+ int is_bcast = 0;
+ __u16 prot, *ptr;
+ int rc;
+
+ if (0 && nic) { /* just to supress warning */
+ return -1;
+ }
+
+ if (fatal_condition) {
+ *size_p = 0;
+ return 0;
+ }
+
+ if (poll_error_buf()) {
+ fatal_condition= 1;
+ fw_fatal= 1;
+ printf("\n *** DEVICE FATAL ERROR ***\n");
+ goto fatal_handling;
+ }
+ else if (drain_eq()) {
+ fatal_condition= 1;
+ printf("\n *** FATAL ERROR ***\n");
+ goto fatal_handling;
+ }
+
+
+ if (retrieve) {
+ /* we actually want to read the packet */
+ if (last_packet_p) {
+ eprintf("");
+ /* there is already a packet that was previously read */
+ memcpy(nic->packet, last_packet_p, last_packet_size);
+ *size_p = last_packet_size;
+ last_packet_p = NULL;
+ return 0;
+ }
+ packet_p = nic->packet;
+ } else {
+ /* we don't want to read the packet,
+ just know if there is one. so we
+ read the packet to a local buffer and
+ we will return that buffer when the ip layer wants
+ another packet */
+ if (last_packet_p) {
+ /* there is already a packet that
+ was not consumend */
+ eprintf("overflow receive packets");
+ return -1;
+ }
+ packet_p = packet;
+ }
+
+ rc = ipoib_read_packet(&prot, packet_p + eth_header_len, &packet_len,
+ &is_bcast);
+ if (rc) {
+ printf("*** FATAL IN RECEIVE FLOW ****\n");
+ goto fatal_handling;
+ }
+
+ if (packet_len == 0) {
+ *size_p = 0;
+ return 0;
+ }
+
+ if (is_bcast) {
+ int i;
+ for (i = 0; i < 6; ++i) {
+ packet_p[i] = 0xff;
+ }
+ } else {
+ packet_p[0] = MLX_ETH_BYTE0;
+ packet_p[1] = MLX_ETH_BYTE1;
+ packet_p[2] = MLX_ETH_BYTE2;
+ packet_p[3] = 0;
+ packet_p[4] = 0;
+ packet_p[5] = 0;
+ }
+
+ memset(packet_p + 6, 0, 6);
+
+ ptr = (__u16 *) (packet_p + 12);
+ *ptr = htons(prot);
+
+ if (!retrieve) {
+ last_packet_p = packet;
+ last_packet_size = packet_len + eth_header_len;
+ *size_p = 0;
+ }
+
+ *size_p = packet_len + eth_header_len;
+ tprintf("packet size=%d, prot=%x\n", *size_p, prot);
+ if (0) {
+ hd(nic->packet, 42);
+ }
+
+ return 0;
+
+fatal_handling:
+ printf("restarting Etherboot\n");
+ sleep(1);
+ longjmp(restart_etherboot, -1);
+ /* we should not be here ... */
+ return -1;
+
+}
diff --git a/src/drivers/net/mlx_ipoib/mt25218.c b/src/drivers/net/mlx_ipoib/mt25218.c
new file mode 100644
index 000000000..7866bf607
--- /dev/null
+++ b/src/drivers/net/mlx_ipoib/mt25218.c
@@ -0,0 +1,245 @@
+/**************************************************************************
+Etherboot - BOOTP/TFTP Bootstrap Program
+Skeleton NIC driver for Etherboot
+***************************************************************************/
+
+/*
+ * 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, or (at
+ * your option) any later version.
+ */
+
+/* to get some global routines like printf */
+#include "etherboot.h"
+/* to get the interface to the body of the program */
+#include "nic.h"
+/* to get the PCI support functions, if this is a PCI NIC */
+#include "pci.h"
+/* to get the ISA support functions, if this is an ISA NIC */
+#include "isa.h"
+
+#include "mt_version.c"
+#include "mt25218_imp.c"
+
+/* NIC specific static variables go here */
+
+int prompt_key(int secs, unsigned char *ch_p)
+{
+ unsigned long tmo;
+ unsigned char ch;
+
+ for (tmo = currticks() + secs * TICKS_PER_SEC; currticks() < tmo;) {
+ if (iskey()) {
+ ch = getchar();
+ /* toupper does not work ... */
+ if (ch == 'v')
+ ch = 'V';
+ if (ch == 'i')
+ ch = 'I';
+ if ((ch=='V') || (ch=='I')) {
+ *ch_p = ch;
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+/**************************************************************************
+IRQ - handle interrupts
+***************************************************************************/
+static void mt25218_irq(struct nic *nic, irq_action_t action)
+{
+ /* This routine is somewhat optional. Etherboot itself
+ * doesn't use interrupts, but they are required under some
+ * circumstances when we're acting as a PXE stack.
+ *
+ * If you don't implement this routine, the only effect will
+ * be that your driver cannot be used via Etherboot's UNDI
+ * API. This won't affect programs that use only the UDP
+ * portion of the PXE API, such as pxelinux.
+ */
+
+ if (0) {
+ nic = NULL;
+ }
+ switch (action) {
+ case DISABLE:
+ case ENABLE:
+ /* Set receive interrupt enabled/disabled state */
+ /*
+ outb ( action == ENABLE ? IntrMaskEnabled : IntrMaskDisabled,
+ nic->ioaddr + IntrMaskRegister );
+ */
+ break;
+ case FORCE:
+ /* Force NIC to generate a receive interrupt */
+ /*
+ outb ( ForceInterrupt, nic->ioaddr + IntrForceRegister );
+ */
+ break;
+ }
+}
+
+/**************************************************************************
+POLL - Wait for a frame
+***************************************************************************/
+static int mt25218_poll(struct nic *nic, int retrieve)
+{
+ /* Work out whether or not there's an ethernet packet ready to
+ * read. Return 0 if not.
+ */
+ /*
+ if ( ! <packet_ready> ) return 0;
+ */
+
+ /* retrieve==0 indicates that we are just checking for the
+ * presence of a packet but don't want to read it just yet.
+ */
+ /*
+ if ( ! retrieve ) return 1;
+ */
+
+ /* Copy data to nic->packet. Data should include the
+ * link-layer header (dest MAC, source MAC, type).
+ * Store length of data in nic->packetlen.
+ * Return true to indicate a packet has been read.
+ */
+ /*
+ nic->packetlen = <packet_length>;
+ memcpy ( nic->packet, <packet_data>, <packet_length> );
+ return 1;
+ */
+ unsigned int size;
+ int rc;
+ rc = poll_imp(nic, retrieve, &size);
+ if (rc) {
+ return 0;
+ }
+
+ if (size == 0) {
+ return 0;
+ }
+
+ nic->packetlen = size;
+
+ return 1;
+}
+
+/**************************************************************************
+TRANSMIT - Transmit a frame
+***************************************************************************/
+static void mt25218_transmit(struct nic *nic, const char *dest, /* Destination */
+ unsigned int type, /* Type */
+ unsigned int size, /* size */
+ const char *packet)
+{ /* Packet */
+ int rc;
+
+ /* Transmit packet to dest MAC address. You will need to
+ * construct the link-layer header (dest MAC, source MAC,
+ * type).
+ */
+ if (nic) {
+ rc = transmit_imp(dest, type, packet, size);
+ if (rc)
+ eprintf("tranmit error");
+ }
+}
+
+/**************************************************************************
+DISABLE - Turn off ethernet interface
+***************************************************************************/
+static void mt25218_disable(struct dev *dev)
+{
+ /* put the card in its initial state */
+ /* This function serves 3 purposes.
+ * This disables DMA and interrupts so we don't receive
+ * unexpected packets or interrupts from the card after
+ * etherboot has finished.
+ * This frees resources so etherboot may use
+ * this driver on another interface
+ * This allows etherboot to reinitialize the interface
+ * if something is something goes wrong.
+ */
+ if (dev || 1) { // ????
+ disable_imp();
+ }
+}
+
+/**************************************************************************
+PROBE - Look for an adapter, this routine's visible to the outside
+***************************************************************************/
+
+static int mt25218_probe(struct dev *dev, struct pci_device *pci)
+{
+ struct nic *nic = (struct nic *)dev;
+ int rc;
+ unsigned char user_request;
+
+ if (pci->vendor != MELLANOX_VENDOR_ID) {
+ eprintf("");
+ return 0;
+ }
+
+ printf("\n");
+ printf("Mellanox Technologies LTD - Boot over IB implementaion\n");
+ printf("Build version = %s\n\n", build_revision);
+
+ verbose_messages = 0;
+ print_info = 0;
+ printf("Press within 3 seconds:\n");
+ printf("V - to increase verbosity\n");
+ printf("I - to print information\n");
+ if (prompt_key(3, &user_request)) {
+ if (user_request == 'V') {
+ printf("User selected verbose messages\n");
+ verbose_messages = 1;
+ }
+ else if (user_request == 'I') {
+ printf("User selected to print information\n");
+ print_info = 1;
+ }
+ }
+ printf("\n");
+
+ adjust_pci_device(pci);
+
+ nic->priv_data = NULL;
+ rc = probe_imp(pci, nic);
+
+ /* give the user a chance to look at the info */
+ if (print_info)
+ sleep(5);
+
+ if (!rc) {
+ /* store NIC parameters */
+ nic->ioaddr = pci->ioaddr & ~3;
+ nic->irqno = pci->irq;
+ /* point to NIC specific routines */
+ dev->disable = mt25218_disable;
+ nic->poll = mt25218_poll;
+ nic->transmit = mt25218_transmit;
+ nic->irq = mt25218_irq;
+
+ return 1;
+ }
+ /* else */
+ return 0;
+}
+
+static struct pci_id mt25218_nics[] = {
+ PCI_ROM(0x15b3, 0x6282, "MT25218", "MT25218 HCA driver"),
+ PCI_ROM(0x15b3, 0x6274, "MT25204", "MT25204 HCA driver"),
+};
+
+static struct pci_driver mt25218_driver __pci_driver = {
+ .type = NIC_DRIVER,
+ .name = "MT25218",
+ .probe = mt25218_probe,
+ .ids = mt25218_nics,
+ .id_count = sizeof(mt25218_nics) / sizeof(mt25218_nics[0]),
+ .class = 0,
+};
diff --git a/src/drivers/net/mlx_ipoib/mt25218.h b/src/drivers/net/mlx_ipoib/mt25218.h
new file mode 100644
index 000000000..15a3feaf0
--- /dev/null
+++ b/src/drivers/net/mlx_ipoib/mt25218.h
@@ -0,0 +1,546 @@
+#ifndef __mt25218_h__
+#define __mt25218_h__
+
+#include "MT25218_PRM.h"
+#include "ib_mad.h"
+
+#define TAVOR_DEVICE_ID 0x5a44
+#define TAVOR_BRIDGE_DEVICE_ID 0x5a46
+#define ARTAVOR_DEVICE_ID 0x6278
+
+#define MEMFREE_RESET_OFFSET 0xF0010
+
+#define INVALID_WQE_LKEY 0x00000100
+
+/*
+ * memfree specific command
+ *
+ */
+#define MEMFREE_CMD_QUERY_ADAPTER 0x006
+#define MEMFREE_CMD_WRITE_MGM 0x026
+#define MEMFREE_CMD_MOD_STAT_CFG 0x034
+#define MEMFREE_CMD_QUERY_FW 0x004
+#define MEMFREE_CMD_ENABLE_LAM 0xff8
+#define MEMFREE_CMD_MAP_FA 0xfff
+#define MEMFREE_CMD_UNMAP_FA 0xffe
+#define MEMFREE_CMD_RUN_FW 0xff6
+#define MEMFREE_CMD_SET_ICM_SIZE 0xffd
+#define MEMFREE_CMD_MAP_ICM_AUX 0xffc
+#define MEMFREE_CMD_MAP_ICM 0xffa
+#define MEMFREE_CMD_QUERY_DEV_LIM 0x003
+
+/*
+ * Tavor specific event types
+ * Only event types that are specific to Tavor
+ * and are used by the driver are listed here
+ */
+#define TAVOR_IF_EV_TYPE_OVERRUN 0x0F
+
+/*
+ * EQ doorbel commands
+ */
+#define EQ_DBELL_CMD_INC_CONS_IDX 1 /* increment Consumer_indx by one */
+#define EQ_DBELL_CMD_ARM_EQ 2 /* Request notifcation for next event (Arm EQ) */
+#define EQ_DBELL_CMD_DISARM_CQ 3 /* Disarm CQ (CQ number is specified in EQ_param) */
+#define EQ_DBELL_CMD_SET_CONS_IDX 4 /* set Consumer_indx to value of EQ_param */
+#define EQ_DBELL_CMD_ALWAYS_ARM 5 /* move EQ to Always Armed state */
+
+/*
+ * CQ doorbel commands
+ */
+#define CQ_DBELL_CMD_INC_CONS_IDX 1
+#define CQ_DBELL_CMD_REQ_NOTIF_SOL_UNSOL 2
+#define CQ_DBELL_CMD_REQ_NOTIF_SOL 3
+#define CQ_DBELL_CMD_SET_CONS_IDX 4
+#define CQ_DBELL_CMD_REQ_NOTIF_MULT 5
+
+#define INPRM_BUF_SZ 4096
+#define INPRM_BUF_ALIGN 4096
+#define OUTPRM_BUF_SZ 4096
+#define OUTPRM_BUF_ALIGN 4096
+
+/*
+ * sizes of parameter blocks used in certain
+ * commands.
+ * TODO: replace them with sizeof
+ * operators of the appropriate structs
+ */
+#define SW2HW_MPT_IBUF_SZ MT_STRUCT_SIZE(arbelprm_mpt_st)
+#define SW2HW_EQ_IBUF_SZ MT_STRUCT_SIZE(arbelprm_eqc_st)
+#define INIT_IB_IBUF_SZ MT_STRUCT_SIZE(arbelprm_init_ib_st)
+#define SW2HW_CQ_IBUF_SZ MT_STRUCT_SIZE(arbelprm_completion_queue_context_st)
+#define QPCTX_IBUF_SZ MT_STRUCT_SIZE(arbelprm_queue_pair_ee_context_entry_st)
+
+#define EQN 0
+#define UAR_IDX 1
+
+#define QPC_OFFSET 0
+#define CQC_OFFSET (QPC_OFFSET + 0x100000)
+#define EQPC_OFFSET (CQC_OFFSET + 0x100000)
+#define EQC_OFFSET (EQPC_OFFSET + 0x100000)
+#define MC_BASE_OFFSET (EQC_OFFSET + 0x100000)
+#define MPT_BASE_OFFSET (MC_BASE_OFFSET + 0x100000)
+#define MTT_BASE_OFFSET (MPT_BASE_OFFSET + 0x100000)
+
+#define LOG2_QPS 7
+#define LOG2_CQS 8
+#define LOG2_EQS 6
+#define LOG2_MC_ENTRY 6 /* 8 QPs per group */
+#define LOG2_MC_GROUPS 3 /* 8 groups */
+#define LOG2_MPT_ENTRIES 5
+
+#define LOG2_EQ_SZ 5
+#define LOG2_CQ_SZ 5
+
+#define NUM_PORTS 2
+
+#define EQE_OWNER_OFFSET 31
+#define EQE_OWNER_VAL_HW 0x80
+
+#define CQE_OWNER_OFFSET 31
+#define CQE_OWNER_VAL_HW 0x80
+
+#define POST_RCV_OFFSET 0x18
+#define POST_SND_OFFSET 0x10
+#define CQ_DBELL_OFFSET 0x20
+#define EQ_DBELL_OFFSET 0x28
+
+#define CQE_ERROR_OPCODE 0xfe
+
+#define OWNER_HW 1
+#define OWNER_SW 0
+
+#define MAX_GATHER 1 /* max gather entries used in send */
+#define MAX_SCATTER 2
+
+#define LOG2_MADS_SND_CQ_SZ LOG2_CQ_SZ
+#define LOG2_MADS_RCV_CQ_SZ LOG2_CQ_SZ
+#define LOG2_IPOIB_SND_CQ_SZ LOG2_CQ_SZ
+#define LOG2_IPOIB_RCV_CQ_SZ LOG2_CQ_SZ
+
+#define NUM_MADS_SND_CQES (1<<LOG2_MADS_SND_CQ_SZ)
+#define NUM_MADS_RCV_CQES (1<<LOG2_MADS_RCV_CQ_SZ)
+#define NUM_IPOIB_SND_CQES (1<<LOG2_IPOIB_SND_CQ_SZ)
+#define NUM_IPOIB_RCV_CQES (1<<LOG2_IPOIB_RCV_CQ_SZ)
+
+/* work queues must be 2^n size with n=0.. */
+#define NUM_MADS_RCV_WQES (1<<1)
+#define NUM_IPOIB_RCV_WQES (1<<1)
+
+#if NUM_MADS_RCV_WQES > NUM_IPOIB_RCV_WQES
+#define MAX_RCV_WQES NUM_MADS_RCV_WQES
+#else
+#define MAX_RCV_WQES NUM_IPOIB_RCV_WQES
+#endif
+
+#define NUM_MADS_SND_WQES (1<<1)
+#define NUM_IPOIB_SND_WQES (1<<1)
+
+#if NUM_MADS_SND_WQES > NUM_IPOIB_SND_WQES
+#define MAX_SND_WQES NUM_MADS_SND_WQES
+#else
+#define MAX_SND_WQES NUM_IPOIB_SND_WQES
+#endif
+
+/* uar context indexes */
+enum {
+ MADS_RCV_CQ_ARM_DB_IDX,
+ MADS_SND_CQ_ARM_DB_IDX,
+ IPOIB_RCV_CQ_ARM_DB_IDX,
+ IPOIB_SND_CQ_ARM_DB_IDX,
+ MADS_SND_QP_DB_IDX,
+ IPOIB_SND_QP_DB_IDX,
+ GROUP_SEP_IDX,
+ START_UNMAPPED_DB_IDX,
+ /* --------------------------
+ unmapped doorbell records
+ -------------------------- */
+ END_UNMAPPED_DB_IDX = 505,
+ MADS_RCV_QP_DB_IDX = 506,
+ IPOIB_RCV_QP_DB_IDX = 507,
+ MADS_RCV_CQ_CI_DB_IDX = 508,
+ MADS_SND_CQ_CI_DB_IDX = 509,
+ IPOIB_RCV_CQ_CI_DB_IDX = 510,
+ IPOIB_SND_CQ_CI_DB_IDX = 511
+};
+
+/* uar resources types */
+enum {
+ UAR_RES_INVALID = 0x0, /* Invalid (not allocated) DoorBell record */
+ UAR_RES_CQ_SET_CI = 0x1, /* CQ SET_CI DoorBell record */
+ UAR_RES_CQ_ARM = 0x2, /* CQ ARM DoorBell record */
+ UAR_RES_SQ_DBELL = 0x3, /* Send Queue DoorBell record */
+ UAR_RES_RQ_DBELL = 0x4, /* Receive Queue DoorBell record */
+ UAR_RES_SRQ_DBELL = 0x5, /* Shared Receive Queue DoorBell record */
+ UAR_RES_GROUP_SEP = 0x7 /* Group Separator record */
+};
+
+enum {
+ TS_RC,
+ TS_UC,
+ TS_RD,
+ TS_UD,
+ TS_MLX
+};
+
+enum {
+ PM_STATE_ARMED = 0,
+ PM_STATE_REARM = 1,
+ PM_STATE_MIGRATED = 3
+};
+
+enum {
+ DOORBEL_RES_SQ = 3,
+ DOORBEL_RES_RQ = 4,
+ DOORBEL_RES_SRQ = 5
+};
+
+struct ib_buffers_st {
+ __u8 send_mad_buf[NUM_MADS_SND_WQES][MAD_BUF_SZ];
+ __u8 rcv_mad_buf[NUM_MADS_RCV_WQES][MAD_BUF_SZ + GRH_SIZE];
+ __u8 ipoib_rcv_buf[NUM_IPOIB_RCV_WQES][IPOIB_RCV_BUF_SZ + GRH_SIZE];
+ __u8 ipoib_rcv_grh_buf[NUM_IPOIB_RCV_WQES][IPOIB_RCV_BUF_SZ];
+ __u8 send_ipoib_buf[NUM_IPOIB_SND_WQES][IPOIB_SND_BUF_SZ];
+};
+
+struct pcidev {
+ unsigned long bar[6];
+ __u32 dev_config_space[64];
+ struct pci_device *dev;
+ __u8 bus;
+ __u8 devfn;
+};
+
+struct dev_pci_struct {
+ struct pcidev dev;
+ struct pcidev br;
+ void *cr_space;
+ void *uar;
+};
+
+struct eq_st {
+ __u8 eqn;
+ __u32 cons_counter;
+ __u32 eq_size;
+ void *ci_base_base_addr;
+ struct eqe_t *eq_buf;
+};
+
+struct eqe_t {
+ __u8 raw[MT_STRUCT_SIZE(arbelprm_event_queue_entry_st)];
+} __attribute__ ((packed));
+
+enum qp_state_e {
+ QP_STATE_RST = 0,
+ QP_STATE_INIT = 1,
+ QP_STATE_RTR = 2,
+ QP_STATE_RTS = 3,
+ QP_STATE_SQEr = 4,
+ QP_STATE_SQD = 5,
+ QP_STATE_ERR = 6,
+ QP_STATE_SQDING = 7,
+ QP_STATE_SUSPEND = 9
+};
+
+struct memory_pointer_st {
+ __u32 byte_count;
+ __u32 lkey;
+ __u32 local_addr_h;
+ __u32 local_addr_l;
+} __attribute__ ((packed));
+
+/* receive wqe descriptor */
+struct recv_wqe_st {
+ /* part referenced by hardware */
+ __u8 control[MT_STRUCT_SIZE(arbelprm_wqe_segment_ctrl_recv_st)];
+ struct memory_pointer_st mpointer[MAX_SCATTER];
+} __attribute__ ((packed));
+
+struct recv_wqe_cont_st {
+ struct recv_wqe_st wqe;
+
+ struct udqp_st *qp; /* qp this wqe is used with */
+} __attribute__ ((packed));
+
+#define RECV_WQE_U_ALIGN 64
+union recv_wqe_u {
+ __u8 align[RECV_WQE_U_ALIGN]; /* this ensures proper alignment */
+ struct recv_wqe_st wqe;
+ struct recv_wqe_cont_st wqe_cont;
+} __attribute__ ((packed));
+
+struct send_doorbell_st {
+ __u8 raw[MT_STRUCT_SIZE(arbelprm_send_doorbell_st)];
+} __attribute__ ((packed));
+
+struct next_control_seg_st {
+ __u8 next[MT_STRUCT_SIZE(arbelprm_wqe_segment_next_st)];
+ __u8 control[MT_STRUCT_SIZE(arbelprm_wqe_segment_ctrl_send_st)];
+} __attribute__ ((packed));
+
+struct ud_seg_st {
+ __u8 av[MT_STRUCT_SIZE(arbelprm_wqe_segment_ud_st)];
+} __attribute__ ((packed));
+
+struct ud_send_wqe_st {
+ struct next_control_seg_st next; /* 16 bytes */
+ struct ud_seg_st udseg; /* 48 bytes */
+ struct memory_pointer_st mpointer[MAX_GATHER]; /* 16 * MAX_GATHER bytes */
+} __attribute__ ((packed));
+
+struct ude_send_wqe_cont_st {
+ struct ud_send_wqe_st wqe;
+
+ struct udqp_st *qp; /* qp this wqe is used with */
+} __attribute__ ((packed));
+
+#define UD_SEND_WQE_U_ALIGN 128
+union ud_send_wqe_u {
+ __u8 align[UD_SEND_WQE_U_ALIGN];
+ struct ude_send_wqe_cont_st wqe_cont;
+} __attribute__ ((packed));
+
+struct address_vector_st {
+ __u8 raw[MT_STRUCT_SIZE(arbelprm_ud_address_vector_st)];
+} __attribute__ ((packed));
+
+struct ud_av_st {
+ struct address_vector_st av;
+ __u32 dest_qp; /* destination qpn */
+ __u32 qkey;
+ __u8 next_free;
+} __attribute__ ((packed));
+
+union ud_av_u {
+ struct ud_av_st ud_av;
+} __attribute__ ((packed));
+
+struct udav_st {
+ union ud_av_u av_array[NUM_AVS];
+ __u8 udav_next_free;
+};
+
+union cqe_st {
+ __u8 good_cqe[MT_STRUCT_SIZE(arbelprm_completion_queue_entry_st)];
+ __u8 error_cqe[MT_STRUCT_SIZE(arbelprm_completion_with_error_st)];
+} __attribute__ ((packed));
+
+struct qp_ee_ctx_t {
+ __u8 raw[MT_STRUCT_SIZE(arbelprm_queue_pair_ee_context_entry_st)];
+} __attribute__ ((packed));
+
+struct qp_ee_state_tarnisition_st {
+ __u32 opt_param_mask;
+ __u32 r1;
+ struct qp_ee_ctx_t ctx;
+ __u32 r2[62];
+} __attribute__ ((packed));
+
+struct cq_dbell_st {
+ __u8 raw[MT_STRUCT_SIZE(arbelprm_cq_cmd_doorbell_st)];
+} __attribute__ ((packed));
+
+struct mad_ifc_inprm_st {
+ union mad_u mad;
+} __attribute__ ((packed));
+
+struct wqe_buf_st {
+ struct ud_send_wqe_st *sndq;
+ struct recv_wqe_st *rcvq;
+};
+
+struct mad_buffer_st {
+ void *buf; /* pointer to a 256 byte buffer */
+ __u8 owner; /* sw or hw ownership BUF_OWNER_SW or BUF_OWNER_HW */
+};
+
+struct rcv_buf_st {
+ void *buf;
+ __u8 busy;
+};
+
+struct ib_eqe_st {
+ __u8 event_type;
+ __u32 cqn;
+};
+
+struct cq_st {
+ __u32 cqn;
+ union cqe_st *cq_buf;
+ __u32 cons_counter; /* consuner counter */
+ __u8 num_cqes;
+ __u32 arm_db_ctx_idx;
+ void *arm_db_ctx_pointer;
+ __u32 ci_db_ctx_idx;
+ void *ci_db_ctx_pointer;
+};
+
+struct udqp_st {
+ /* cq used by this QP */
+ struct cq_st snd_cq;
+ struct cq_st rcv_cq;
+
+ /* QP related data */
+ __u32 qpn; /* QP number */
+
+ __u32 qkey;
+
+ __u8 recv_wqe_cur_free;
+ __u8 recv_wqe_alloc_idx;
+ __u8 max_recv_wqes;
+ void *rcv_bufs[MAX_RCV_WQES];
+ union recv_wqe_u *rcv_wq; /* receive work queue */
+ struct recv_wqe_st *last_posted_rcv_wqe;
+
+ __u8 snd_wqe_cur_free;
+ __u8 snd_wqe_alloc_idx;
+ __u8 max_snd_wqes;
+ void *snd_bufs[MAX_SND_WQES];
+ __u16 send_buf_sz;
+ __u16 rcv_buf_sz;
+ union ud_send_wqe_u *snd_wq; /* send work queue */
+ struct ud_send_wqe_st *last_posted_snd_wqe;
+ /* pointers to uar context entries */
+ void *send_uar_context;
+ __u16 post_send_counter;
+ void *rcv_uar_context;
+ __u16 post_rcv_counter;
+ __u32 snd_db_record_index;
+ __u32 rcv_db_record_index;
+};
+
+struct device_ib_data_st {
+ __u32 mkey;
+ __u32 pd;
+ __u8 port;
+ __u32 qkey;
+ struct eq_st eq;
+ struct udav_st udav;
+ struct udqp_st mads_qp;
+ struct udqp_st ipoib_qp;
+ void *clr_int_addr;
+ __u32 clr_int_data;
+ __u32 uar_idx;
+ void *uar_context_base;
+ void *error_buf_addr;
+ __u32 error_buf_size;
+};
+
+struct query_fw_st {
+ __u16 fw_rev_major;
+ __u16 fw_rev_minor;
+ __u16 fw_rev_subminor;
+ __u32 error_buf_start_h;
+ __u32 error_buf_start_l;
+ __u32 error_buf_size;
+ __u32 fw_pages;
+ struct addr_64_st eq_ci_table;
+ struct addr_64_st clear_int_addr;
+};
+
+struct query_adapter_st {
+ __u8 intapin;
+};
+
+struct vpm_entry_st {
+ __u32 va_h;
+ __u32 va_l;
+ __u32 pa_h;
+ __u32 pa_l;
+ __u8 log2_size;
+};
+
+#define MAX_VPM_PER_CALL 1
+
+struct map_icm_st {
+ __u32 num_vpm;
+ struct vpm_entry_st vpm_arr[MAX_VPM_PER_CALL];
+};
+
+struct init_hca_st {
+ __u32 qpc_base_addr_h;
+ __u32 qpc_base_addr_l;
+ __u8 log_num_of_qp;
+
+ __u32 eec_base_addr_h;
+ __u32 eec_base_addr_l;
+ __u8 log_num_of_ee;
+
+ __u32 srqc_base_addr_h;
+ __u32 srqc_base_addr_l;
+ __u8 log_num_of_srq;
+
+ __u32 cqc_base_addr_h;
+ __u32 cqc_base_addr_l;
+ __u8 log_num_of_cq;
+
+ __u32 eqpc_base_addr_h;
+ __u32 eqpc_base_addr_l;
+
+ __u32 eeec_base_addr_h;
+ __u32 eeec_base_addr_l;
+
+ __u32 eqc_base_addr_h;
+ __u32 eqc_base_addr_l;
+ __u8 log_num_of_eq;
+
+ __u32 rdb_base_addr_h;
+ __u32 rdb_base_addr_l;
+
+ __u32 mc_base_addr_h;
+ __u32 mc_base_addr_l;
+ __u16 log_mc_table_entry_sz;
+ __u32 mc_table_hash_sz;
+ __u8 log_mc_table_sz;
+
+ __u32 mpt_base_addr_h;
+ __u32 mpt_base_addr_l;
+ __u8 log_mpt_sz;
+ __u32 mtt_base_addr_h;
+ __u32 mtt_base_addr_l;
+ __u8 log_max_uars;
+};
+
+struct dev_lim_st {
+ __u8 log2_rsvd_qps;
+ __u16 qpc_entry_sz;
+
+ __u8 log2_rsvd_srqs;
+ __u16 srq_entry_sz;
+
+ __u8 log2_rsvd_ees;
+ __u16 eec_entry_sz;
+
+ __u8 log2_rsvd_cqs;
+ __u16 cqc_entry_sz;
+
+ __u8 log2_rsvd_mtts;
+ __u16 mtt_entry_sz;
+
+ __u8 log2_rsvd_mrws;
+ __u16 mpt_entry_sz;
+
+ __u8 log2_rsvd_rdbs;
+
+ __u16 eqc_entry_sz;
+
+ __u32 max_icm_size_l;
+ __u32 max_icm_size_h;
+
+ __u8 uar_sz;
+ __u8 num_rsvd_uars;
+};
+
+static int create_udqp(struct udqp_st *qp);
+static int destroy_udqp(struct udqp_st *qp);
+static void *get_send_wqe_buf(void *wqe, __u8 index);
+static void *get_rcv_wqe_buf(void *wqe, __u8 index);
+
+static struct recv_wqe_st *alloc_rcv_wqe(struct udqp_st *qp);
+static int free_wqe(void *wqe);
+static int poll_cq(void *cqh, union cqe_st *cqe_p, __u8 * num_cqes);
+static int poll_eq(struct ib_eqe_st *ib_eqe_p, __u8 * num_eqes);
+static int post_rcv_buf(struct udqp_st *qp, struct recv_wqe_st *rcv_wqe);
+static __u32 dev_get_qpn(void *qph);
+
+#endif /* __mt25218_h__ */
diff --git a/src/drivers/net/mlx_ipoib/mt25218_imp.c b/src/drivers/net/mlx_ipoib/mt25218_imp.c
new file mode 100644
index 000000000..fe407041e
--- /dev/null
+++ b/src/drivers/net/mlx_ipoib/mt25218_imp.c
@@ -0,0 +1,230 @@
+typedef uint32_t __u32;
+typedef uint16_t __u16;
+typedef uint8_t __u8;
+
+static int verbose_messages=0;
+static int print_info=0;
+static int fatal_condition=0;
+static int fw_fatal;
+
+#define tprintf(fmt, a...) \
+ do { \
+ if ( verbose_messages ) { \
+ printf("%s:%d: " fmt "\n", __func__, __LINE__, ##a); \
+ } \
+ } \
+ while(0)
+
+#define eprintf(fmt, a...) \
+ printf("%s:%d: " fmt "\n", __func__, __LINE__, ##a)
+
+static void cpu_to_be_buf(void *buf, int size)
+{
+ int dw_sz = size >> 2, i;
+
+ for (i = 0; i < dw_sz; ++i) {
+ ((__u32 *) buf)[i] = cpu_to_be32(((__u32 *) buf)[i]);
+ }
+}
+
+static void be_to_cpu_buf(void *buf, int size)
+{
+ int dw_sz = size >> 2, i;
+ u32 *p = buf;
+
+ for (i = 0; i < dw_sz; ++i) {
+ p[i] = be32_to_cpu(p[i]);
+ }
+}
+
+#include "timer.h"
+#include "cmdif_mt25218.c"
+#include "cmdif_comm.c"
+#include "ib_mt25218.c"
+#include "ib_mad.c"
+#include "ib_driver.c"
+#include "ipoib.c"
+
+static int probe_imp(struct pci_device *pci, struct nic *nic)
+{
+ int rc;
+
+ if (0 && nic) { /* just to supress warning */
+ return 0;
+ }
+
+ fatal_condition= 0;
+ fw_fatal= 0;
+
+ tprintf("");
+ rc = ipoib_init(pci);
+ if (rc)
+ return rc;
+
+ tprintf("");
+
+ return rc;
+}
+
+static int disable_imp(void)
+{
+ int rc;
+
+ rc = ipoib_close(fw_fatal);
+
+ return rc;
+}
+
+static int transmit_imp(const char *dest, /* Destination */
+ unsigned int type, /* Type */
+ const char *packet, /* Packet */
+ unsigned int size)
+{ /* size */
+ int rc;
+
+ if (fatal_condition) {
+ /* since the transmit function does not return a value
+ we return success but do nothing to suppress error messages */
+ return 0;
+ }
+
+ rc = ipoib_send_packet(dest, type, packet, size);
+ if (rc) {
+ printf("*** ERROR IN SEND FLOW ***\n");
+ printf("restarting Etherboot\n");
+ sleep(1);
+ longjmp(restart_etherboot, -1);
+ /* we should not be here ... */
+ return -1;
+ }
+
+ return rc;
+}
+
+static void hd(void *where, int n)
+{
+ int i;
+
+ while (n > 0) {
+ printf("%X ", where);
+ for (i = 0; i < ((n > 16) ? 16 : n); i++)
+ printf(" %hhX", ((char *)where)[i]);
+ printf("\n");
+ n -= 16;
+ where += 16;
+ }
+}
+
+static int poll_imp(struct nic *nic, int retrieve, unsigned int *size_p)
+{
+ static char packet[2048];
+ static char *last_packet_p = NULL;
+ static unsigned long last_packet_size;
+ char *packet_p;
+ const int eth_header_len = 14;
+ unsigned int packet_len;
+ int is_bcast = 0;
+ __u16 prot, *ptr;
+ int rc;
+
+ if (0 && nic) { /* just to supress warning */
+ return -1;
+ }
+
+ if (fatal_condition) {
+ *size_p = 0;
+ return 0;
+ }
+
+ if (poll_error_buf()) {
+ fatal_condition= 1;
+ fw_fatal= 1;
+ printf("\n *** DEVICE FATAL ERROR ***\n");
+ goto fatal_handling;
+ }
+ else if (drain_eq()) {
+ fatal_condition= 1;
+ printf("\n *** FATAL ERROR ***\n");
+ goto fatal_handling;
+ }
+
+
+ if (retrieve) {
+ /* we actually want to read the packet */
+ if (last_packet_p) {
+ eprintf("");
+ /* there is already a packet that was previously read */
+ memcpy(nic->packet, last_packet_p, last_packet_size);
+ *size_p = last_packet_size;
+ last_packet_p = NULL;
+ return 0;
+ }
+ packet_p = nic->packet;
+ } else {
+ /* we don't want to read the packet,
+ just know if there is one. so we
+ read the packet to a local buffer and
+ we will return that buffer when the ip layer wants
+ another packet */
+ if (last_packet_p) {
+ /* there is already a packet that
+ was not consumend */
+ eprintf("overflow receive packets");
+ return -1;
+ }
+ packet_p = packet;
+ }
+
+ rc = ipoib_read_packet(&prot, packet_p + eth_header_len, &packet_len,
+ &is_bcast);
+ if (rc) {
+ printf("*** FATAL IN RECEIVE FLOW ****\n");
+ goto fatal_handling;
+ }
+
+ if (packet_len == 0) {
+ *size_p = 0;
+ return 0;
+ }
+
+ if (is_bcast) {
+ int i;
+ for (i = 0; i < 6; ++i) {
+ packet_p[i] = 0xff;
+ }
+ } else {
+ packet_p[0] = MLX_ETH_BYTE0;
+ packet_p[1] = MLX_ETH_BYTE1;
+ packet_p[2] = MLX_ETH_BYTE2;
+ packet_p[3] = 0;
+ packet_p[4] = 0;
+ packet_p[5] = 0;
+ }
+
+ memset(packet_p + 6, 0, 6);
+
+ ptr = (__u16 *) (packet_p + 12);
+ *ptr = htons(prot);
+
+ if (!retrieve) {
+ last_packet_p = packet;
+ last_packet_size = packet_len + eth_header_len;
+ *size_p = 0;
+ }
+
+ *size_p = packet_len + eth_header_len;
+ tprintf("packet size=%d, prot=%x\n", *size_p, prot);
+ if (0) {
+ hd(nic->packet, 42);
+ }
+
+ return 0;
+
+fatal_handling:
+ printf("restarting Etherboot\n");
+ sleep(1);
+ longjmp(restart_etherboot, -1);
+ /* we should not be here ... */
+ return -1;
+
+}
diff --git a/src/drivers/net/mlx_ipoib/mt_version.c b/src/drivers/net/mlx_ipoib/mt_version.c
new file mode 100644
index 000000000..2dbd67a6a
--- /dev/null
+++ b/src/drivers/net/mlx_ipoib/mt_version.c
@@ -0,0 +1,23 @@
+/*
+ This software is available to you under a choice of one of two
+ licenses. You may choose to be licensed under the terms of the GNU
+ General Public License (GPL) Version 2, available at
+ <http://www.fsf.org/copyleft/gpl.html>, or the OpenIB.org BSD
+ license, available in the LICENSE.TXT file accompanying this
+ software. These details are also available at
+ <http://openib.org/license.html>.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+
+ Copyright (c) 2004 Mellanox Technologies Ltd. All rights reserved.
+*/
+
+/* definition of the build version goes here */
+const char *build_revision= "113";
diff --git a/src/drivers/net/mtd80x.c b/src/drivers/net/mtd80x.c
index 3d974abc3..c7754a94f 100644
--- a/src/drivers/net/mtd80x.c
+++ b/src/drivers/net/mtd80x.c
@@ -30,13 +30,6 @@
/* to get the PCI support functions, if this is a PCI NIC */
#include "pci.h"
-typedef unsigned char u8;
-typedef signed char s8;
-typedef unsigned short u16;
-typedef signed short s16;
-typedef unsigned int u32;
-typedef signed int s32;
-
/* 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))
diff --git a/src/drivers/net/natsemi.c b/src/drivers/net/natsemi.c
index 003b97983..e8f6d81c1 100644
--- a/src/drivers/net/natsemi.c
+++ b/src/drivers/net/natsemi.c
@@ -71,13 +71,6 @@
#define NUM_RX_DESC 4 /* Number of Rx descriptor registers. */
-typedef uint8_t u8;
-typedef int8_t s8;
-typedef uint16_t u16;
-typedef int16_t s16;
-typedef uint32_t u32;
-typedef int32_t s32;
-
/* helpful macroes if on a big_endian machine for changing byte order.
not strictly needed on Intel */
#define get_unaligned(ptr) (*(ptr))
@@ -611,7 +604,7 @@ natsemi_transmit(struct nic *nic,
const char *p) /* Packet */
{
u32 to, nstype;
- u32 tx_status;
+ volatile u32 tx_status;
/* Stop the transmitter */
outl(TxOff, ioaddr + ChipCmd);
@@ -650,7 +643,7 @@ natsemi_transmit(struct nic *nic,
to = currticks() + TX_TIMEOUT;
- while ((((volatile u32) tx_status=txd.cmdsts) & OWN) && (currticks() < to))
+ while (((tx_status=txd.cmdsts) & OWN) && (currticks() < to))
/* wait */ ;
if (currticks() >= to) {
diff --git a/src/drivers/net/ns83820.c b/src/drivers/net/ns83820.c
index d4fafb686..df9eec5a2 100755
--- a/src/drivers/net/ns83820.c
+++ b/src/drivers/net/ns83820.c
@@ -53,13 +53,6 @@
#define dprintf(x)
#endif
-typedef unsigned char u8;
-typedef signed char s8;
-typedef unsigned short u16;
-typedef signed short s16;
-typedef unsigned int u32;
-typedef signed int s32;
-
#define HZ 100
/* Condensed operations for readability. */
diff --git a/src/drivers/net/pcnet32.c b/src/drivers/net/pcnet32.c
index 5a0bb14cd..4255269bb 100644
--- a/src/drivers/net/pcnet32.c
+++ b/src/drivers/net/pcnet32.c
@@ -54,13 +54,6 @@
#define drv_version "v1.3"
#define drv_date "03-29-2004"
-typedef unsigned char u8;
-typedef signed char s8;
-typedef unsigned short u16;
-typedef signed short s16;
-typedef unsigned int u32;
-typedef signed int s32;
-
static u32 ioaddr; /* Globally used for the card's io address */
static struct nic_operations pcnet32_operations;
static struct pci_driver pcnet32_driver;
diff --git a/src/drivers/net/r8169.c b/src/drivers/net/r8169.c
index ad3b62bd6..427fad0f8 100644
--- a/src/drivers/net/r8169.c
+++ b/src/drivers/net/r8169.c
@@ -52,13 +52,6 @@
#define drv_version "v1.6"
#define drv_date "03-27-2004"
-typedef unsigned char u8;
-typedef signed char s8;
-typedef unsigned short u16;
-typedef signed short s16;
-typedef unsigned int u32;
-typedef signed int s32;
-
#define HZ 1000
static u32 ioaddr;
diff --git a/src/drivers/net/sis900.c b/src/drivers/net/sis900.c
index b5ba3f08b..c2cb94e87 100644
--- a/src/drivers/net/sis900.c
+++ b/src/drivers/net/sis900.c
@@ -1097,7 +1097,7 @@ sis900_transmit(struct nic *nic,
const char *p) /* Packet */
{
u32 to, nstype;
- u32 tx_status;
+ volatile u32 tx_status;
/* Stop the transmitter */
outl(TxDIS | inl(ioaddr + cr), ioaddr + cr);
@@ -1136,7 +1136,7 @@ sis900_transmit(struct nic *nic,
to = currticks() + TX_TIMEOUT;
- while ((((volatile u32) tx_status=txd.cmdsts) & OWN) && (currticks() < to))
+ while (((tx_status=txd.cmdsts) & OWN) && (currticks() < to))
/* wait */ ;
if (currticks() >= to) {
diff --git a/src/drivers/net/sis900.h b/src/drivers/net/sis900.h
index 89aa3aa5a..e88e111d4 100644
--- a/src/drivers/net/sis900.h
+++ b/src/drivers/net/sis900.h
@@ -363,13 +363,6 @@ enum sis630_revision_id {
#define NUM_RX_DESC 4 /* Number of Rx descriptor registers. */
-typedef unsigned char u8;
-typedef signed char s8;
-typedef unsigned short u16;
-typedef signed short s16;
-typedef unsigned int u32;
-typedef signed int s32;
-
/* Time in ticks before concluding the transmitter is hung. */
#define TX_TIMEOUT (4*TICKS_PER_SEC)
diff --git a/src/drivers/net/smc9000.c b/src/drivers/net/smc9000.c
index 7c6947777..43f04f061 100644
--- a/src/drivers/net/smc9000.c
+++ b/src/drivers/net/smc9000.c
@@ -29,9 +29,16 @@
#define LINUX_OUT_MACROS 1
#define SMC9000_DEBUG 0
+#if SMC9000_DEBUG > 1
+#define PRINTK2 printf
+#else
+#define PRINTK2(args...)
+#endif
+
#include "etherboot.h"
#include "nic.h"
#include "isa.h"
+#include "timer.h"
#include "smc9000.h"
# define _outb outb
@@ -47,11 +54,449 @@ static const char *chip_ids[ 15 ] = {
NULL,
/* 7 */ "SMC91C100",
/* 8 */ "SMC91C100FD",
- NULL, NULL, NULL,
+ /* 9 */ "SMC91C11xFD",
+ NULL, NULL,
NULL, NULL, NULL
};
static const char smc91c96_id[] = "SMC91C96";
+/*------------------------------------------------------------
+ . Reads a register from the MII Management serial interface
+ .-------------------------------------------------------------*/
+static word smc_read_phy_register(int ioaddr, byte phyaddr, byte phyreg)
+{
+ int oldBank;
+ unsigned int i;
+ byte mask;
+ word mii_reg;
+ byte bits[64];
+ int clk_idx = 0;
+ int input_idx;
+ word phydata;
+
+ // 32 consecutive ones on MDO to establish sync
+ for (i = 0; i < 32; ++i)
+ bits[clk_idx++] = MII_MDOE | MII_MDO;
+
+ // Start code <01>
+ bits[clk_idx++] = MII_MDOE;
+ bits[clk_idx++] = MII_MDOE | MII_MDO;
+
+ // Read command <10>
+ bits[clk_idx++] = MII_MDOE | MII_MDO;
+ bits[clk_idx++] = MII_MDOE;
+
+ // Output the PHY address, msb first
+ mask = (byte)0x10;
+ for (i = 0; i < 5; ++i)
+ {
+ if (phyaddr & mask)
+ bits[clk_idx++] = MII_MDOE | MII_MDO;
+ else
+ bits[clk_idx++] = MII_MDOE;
+
+ // Shift to next lowest bit
+ mask >>= 1;
+ }
+
+ // Output the phy register number, msb first
+ mask = (byte)0x10;
+ for (i = 0; i < 5; ++i)
+ {
+ if (phyreg & mask)
+ bits[clk_idx++] = MII_MDOE | MII_MDO;
+ else
+ bits[clk_idx++] = MII_MDOE;
+
+ // Shift to next lowest bit
+ mask >>= 1;
+ }
+
+ // Tristate and turnaround (2 bit times)
+ bits[clk_idx++] = 0;
+ //bits[clk_idx++] = 0;
+
+ // Input starts at this bit time
+ input_idx = clk_idx;
+
+ // Will input 16 bits
+ for (i = 0; i < 16; ++i)
+ bits[clk_idx++] = 0;
+
+ // Final clock bit
+ bits[clk_idx++] = 0;
+
+ // Save the current bank
+ oldBank = inw( ioaddr+BANK_SELECT );
+
+ // Select bank 3
+ SMC_SELECT_BANK(ioaddr, 3);
+
+ // Get the current MII register value
+ mii_reg = inw( ioaddr+MII_REG );
+
+ // Turn off all MII Interface bits
+ mii_reg &= ~(MII_MDOE|MII_MCLK|MII_MDI|MII_MDO);
+
+ // Clock all 64 cycles
+ for (i = 0; i < sizeof(bits); ++i)
+ {
+ // Clock Low - output data
+ outw( mii_reg | bits[i], ioaddr+MII_REG );
+ udelay(50);
+
+
+ // Clock Hi - input data
+ outw( mii_reg | bits[i] | MII_MCLK, ioaddr+MII_REG );
+ udelay(50);
+ bits[i] |= inw( ioaddr+MII_REG ) & MII_MDI;
+ }
+
+ // Return to idle state
+ // Set clock to low, data to low, and output tristated
+ outw( mii_reg, ioaddr+MII_REG );
+ udelay(50);
+
+ // Restore original bank select
+ SMC_SELECT_BANK(ioaddr, oldBank);
+
+ // Recover input data
+ phydata = 0;
+ for (i = 0; i < 16; ++i)
+ {
+ phydata <<= 1;
+
+ if (bits[input_idx++] & MII_MDI)
+ phydata |= 0x0001;
+ }
+
+#if (SMC_DEBUG > 2 )
+ printf("smc_read_phy_register(): phyaddr=%x,phyreg=%x,phydata=%x\n",
+ phyaddr, phyreg, phydata);
+#endif
+
+ return(phydata);
+}
+
+
+/*------------------------------------------------------------
+ . Writes a register to the MII Management serial interface
+ .-------------------------------------------------------------*/
+static void smc_write_phy_register(int ioaddr,
+ byte phyaddr, byte phyreg, word phydata)
+{
+ int oldBank;
+ unsigned int i;
+ word mask;
+ word mii_reg;
+ byte bits[65];
+ int clk_idx = 0;
+
+ // 32 consecutive ones on MDO to establish sync
+ for (i = 0; i < 32; ++i)
+ bits[clk_idx++] = MII_MDOE | MII_MDO;
+
+ // Start code <01>
+ bits[clk_idx++] = MII_MDOE;
+ bits[clk_idx++] = MII_MDOE | MII_MDO;
+
+ // Write command <01>
+ bits[clk_idx++] = MII_MDOE;
+ bits[clk_idx++] = MII_MDOE | MII_MDO;
+
+ // Output the PHY address, msb first
+ mask = (byte)0x10;
+ for (i = 0; i < 5; ++i)
+ {
+ if (phyaddr & mask)
+ bits[clk_idx++] = MII_MDOE | MII_MDO;
+ else
+ bits[clk_idx++] = MII_MDOE;
+
+ // Shift to next lowest bit
+ mask >>= 1;
+ }
+
+ // Output the phy register number, msb first
+ mask = (byte)0x10;
+ for (i = 0; i < 5; ++i)
+ {
+ if (phyreg & mask)
+ bits[clk_idx++] = MII_MDOE | MII_MDO;
+ else
+ bits[clk_idx++] = MII_MDOE;
+
+ // Shift to next lowest bit
+ mask >>= 1;
+ }
+
+ // Tristate and turnaround (2 bit times)
+ bits[clk_idx++] = 0;
+ bits[clk_idx++] = 0;
+
+ // Write out 16 bits of data, msb first
+ mask = 0x8000;
+ for (i = 0; i < 16; ++i)
+ {
+ if (phydata & mask)
+ bits[clk_idx++] = MII_MDOE | MII_MDO;
+ else
+ bits[clk_idx++] = MII_MDOE;
+
+ // Shift to next lowest bit
+ mask >>= 1;
+ }
+
+ // Final clock bit (tristate)
+ bits[clk_idx++] = 0;
+
+ // Save the current bank
+ oldBank = inw( ioaddr+BANK_SELECT );
+
+ // Select bank 3
+ SMC_SELECT_BANK(ioaddr, 3);
+
+ // Get the current MII register value
+ mii_reg = inw( ioaddr+MII_REG );
+
+ // Turn off all MII Interface bits
+ mii_reg &= ~(MII_MDOE|MII_MCLK|MII_MDI|MII_MDO);
+
+ // Clock all cycles
+ for (i = 0; i < sizeof(bits); ++i)
+ {
+ // Clock Low - output data
+ outw( mii_reg | bits[i], ioaddr+MII_REG );
+ udelay(50);
+
+
+ // Clock Hi - input data
+ outw( mii_reg | bits[i] | MII_MCLK, ioaddr+MII_REG );
+ udelay(50);
+ bits[i] |= inw( ioaddr+MII_REG ) & MII_MDI;
+ }
+
+ // Return to idle state
+ // Set clock to low, data to low, and output tristated
+ outw( mii_reg, ioaddr+MII_REG );
+ udelay(50);
+
+ // Restore original bank select
+ SMC_SELECT_BANK(ioaddr, oldBank);
+
+#if (SMC_DEBUG > 2 )
+ printf("smc_write_phy_register(): phyaddr=%x,phyreg=%x,phydata=%x\n",
+ phyaddr, phyreg, phydata);
+#endif
+}
+
+
+/*------------------------------------------------------------
+ . Finds and reports the PHY address
+ .-------------------------------------------------------------*/
+static int smc_detect_phy(int ioaddr, byte *pphyaddr)
+{
+ word phy_id1;
+ word phy_id2;
+ int phyaddr;
+ int found = 0;
+
+ // Scan all 32 PHY addresses if necessary
+ for (phyaddr = 0; phyaddr < 32; ++phyaddr)
+ {
+ // Read the PHY identifiers
+ phy_id1 = smc_read_phy_register(ioaddr, phyaddr, PHY_ID1_REG);
+ phy_id2 = smc_read_phy_register(ioaddr, phyaddr, PHY_ID2_REG);
+
+ // Make sure it is a valid identifier
+ if ((phy_id2 > 0x0000) && (phy_id2 < 0xffff) &&
+ (phy_id1 > 0x0000) && (phy_id1 < 0xffff))
+ {
+ if ((phy_id1 != 0x8000) && (phy_id2 != 0x8000))
+ {
+ // Save the PHY's address
+ *pphyaddr = phyaddr;
+ found = 1;
+ break;
+ }
+ }
+ }
+
+ if (!found)
+ {
+ printf("No PHY found\n");
+ return(0);
+ }
+
+ // Set the PHY type
+ if ( (phy_id1 == 0x0016) && ((phy_id2 & 0xFFF0) == 0xF840 ) )
+ {
+ printf("PHY=LAN83C183 (LAN91C111 Internal)\n");
+ }
+
+ if ( (phy_id1 == 0x0282) && ((phy_id2 & 0xFFF0) == 0x1C50) )
+ {
+ printf("PHY=LAN83C180\n");
+ }
+
+ return(1);
+}
+
+/*------------------------------------------------------------
+ . Configures the specified PHY using Autonegotiation. Calls
+ . smc_phy_fixed() if the user has requested a certain config.
+ .-------------------------------------------------------------*/
+static void smc_phy_configure(int ioaddr)
+{
+ int timeout;
+ byte phyaddr;
+ word my_phy_caps; // My PHY capabilities
+ word my_ad_caps; // My Advertised capabilities
+ word status;
+ int failed = 0;
+ int rpc_cur_mode = RPC_DEFAULT;
+ int lastPhy18;
+
+ // Find the address and type of our phy
+ if (!smc_detect_phy(ioaddr, &phyaddr))
+ {
+ return;
+ }
+
+ // Reset the PHY, setting all other bits to zero
+ smc_write_phy_register(ioaddr, phyaddr, PHY_CNTL_REG, PHY_CNTL_RST);
+
+ // Wait for the reset to complete, or time out
+ timeout = 6; // Wait up to 3 seconds
+ while (timeout--)
+ {
+ if (!(smc_read_phy_register(ioaddr, phyaddr, PHY_CNTL_REG)
+ & PHY_CNTL_RST))
+ {
+ // reset complete
+ break;
+ }
+
+ mdelay(500); // wait 500 millisecs
+ }
+
+ if (timeout < 1)
+ {
+ PRINTK2("PHY reset timed out\n");
+ return;
+ }
+
+ // Read PHY Register 18, Status Output
+ lastPhy18 = smc_read_phy_register(ioaddr, phyaddr, PHY_INT_REG);
+
+ // Enable PHY Interrupts (for register 18)
+ // Interrupts listed here are disabled
+ smc_write_phy_register(ioaddr, phyaddr, PHY_MASK_REG,
+ PHY_INT_LOSSSYNC | PHY_INT_CWRD | PHY_INT_SSD |
+ PHY_INT_ESD | PHY_INT_RPOL | PHY_INT_JAB |
+ PHY_INT_SPDDET | PHY_INT_DPLXDET);
+
+ /* Configure the Receive/Phy Control register */
+ SMC_SELECT_BANK(ioaddr, 0);
+ outw( rpc_cur_mode, ioaddr + RPC_REG );
+
+ // Copy our capabilities from PHY_STAT_REG to PHY_AD_REG
+ my_phy_caps = smc_read_phy_register(ioaddr, phyaddr, PHY_STAT_REG);
+ my_ad_caps = PHY_AD_CSMA; // I am CSMA capable
+
+ if (my_phy_caps & PHY_STAT_CAP_T4)
+ my_ad_caps |= PHY_AD_T4;
+
+ if (my_phy_caps & PHY_STAT_CAP_TXF)
+ my_ad_caps |= PHY_AD_TX_FDX;
+
+ if (my_phy_caps & PHY_STAT_CAP_TXH)
+ my_ad_caps |= PHY_AD_TX_HDX;
+
+ if (my_phy_caps & PHY_STAT_CAP_TF)
+ my_ad_caps |= PHY_AD_10_FDX;
+
+ if (my_phy_caps & PHY_STAT_CAP_TH)
+ my_ad_caps |= PHY_AD_10_HDX;
+
+ // Update our Auto-Neg Advertisement Register
+ smc_write_phy_register(ioaddr, phyaddr, PHY_AD_REG, my_ad_caps);
+
+ PRINTK2("phy caps=%x\n", my_phy_caps);
+ PRINTK2("phy advertised caps=%x\n", my_ad_caps);
+
+ // Restart auto-negotiation process in order to advertise my caps
+ smc_write_phy_register( ioaddr, phyaddr, PHY_CNTL_REG,
+ PHY_CNTL_ANEG_EN | PHY_CNTL_ANEG_RST );
+
+ // Wait for the auto-negotiation to complete. This may take from
+ // 2 to 3 seconds.
+ // Wait for the reset to complete, or time out
+ timeout = 20; // Wait up to 10 seconds
+ while (timeout--)
+ {
+ status = smc_read_phy_register(ioaddr, phyaddr, PHY_STAT_REG);
+ if (status & PHY_STAT_ANEG_ACK)
+ {
+ // auto-negotiate complete
+ break;
+ }
+
+ mdelay(500); // wait 500 millisecs
+
+ // Restart auto-negotiation if remote fault
+ if (status & PHY_STAT_REM_FLT)
+ {
+ PRINTK2("PHY remote fault detected\n");
+
+ // Restart auto-negotiation
+ PRINTK2("PHY restarting auto-negotiation\n");
+ smc_write_phy_register( ioaddr, phyaddr, PHY_CNTL_REG,
+ PHY_CNTL_ANEG_EN | PHY_CNTL_ANEG_RST |
+ PHY_CNTL_SPEED | PHY_CNTL_DPLX);
+ }
+ }
+
+ if (timeout < 1)
+ {
+ PRINTK2("PHY auto-negotiate timed out\n");
+ failed = 1;
+ }
+
+ // Fail if we detected an auto-negotiate remote fault
+ if (status & PHY_STAT_REM_FLT)
+ {
+ PRINTK2("PHY remote fault detected\n");
+ failed = 1;
+ }
+
+ // Set our sysctl parameters to match auto-negotiation results
+ if ( lastPhy18 & PHY_INT_SPDDET )
+ {
+ PRINTK2("PHY 100BaseT\n");
+ rpc_cur_mode |= RPC_SPEED;
+ }
+ else
+ {
+ PRINTK2("PHY 10BaseT\n");
+ rpc_cur_mode &= ~RPC_SPEED;
+ }
+
+ if ( lastPhy18 & PHY_INT_DPLXDET )
+ {
+ PRINTK2("PHY Full Duplex\n");
+ rpc_cur_mode |= RPC_DPLX;
+ }
+ else
+ {
+ PRINTK2("PHY Half Duplex\n");
+ rpc_cur_mode &= ~RPC_DPLX;
+ }
+
+ // Re-Configure the Receive/Phy Control register
+ outw( rpc_cur_mode, ioaddr + RPC_REG );
+}
+
/*
* Function: smc_reset( int ioaddr )
* Purpose:
@@ -476,6 +921,8 @@ static int smc9000_probe ( struct nic *nic, struct isa_device *isa ) {
nic->ioaddr + CONFIG );
}
+ smc_phy_configure(nic->ioaddr);
+
nic->nic_op = &smc9000_operations;
return 1;
}
diff --git a/src/drivers/net/smc9000.h b/src/drivers/net/smc9000.h
index ac7f91639..ffe5bbdb9 100644
--- a/src/drivers/net/smc9000.h
+++ b/src/drivers/net/smc9000.h
@@ -91,6 +91,24 @@ typedef unsigned long int dword;
#define MCR 10
/* 12 is reserved */
+// Receive/Phy Control Register
+/* BANK 0 */
+#define RPC_REG 0x000A
+#define RPC_SPEED 0x2000 // When 1 PHY is in 100Mbps mode.
+#define RPC_DPLX 0x1000 // When 1 PHY is in Full-Duplex Mode
+#define RPC_ANEG 0x0800 // When 1 PHY is in Auto-Negotiate Mode
+#define RPC_LSXA_SHFT 5 // Bits to shift LS2A,LS1A,LS0A to lsb
+#define RPC_LSXB_SHFT 2 // Bits to get LS2B,LS1B,LS0B to lsb
+#define RPC_LED_100_10 (0x00) // LED = 100Mbps OR's with 10Mbps link detect
+#define RPC_LED_RES (0x01) // LED = Reserved
+#define RPC_LED_10 (0x02) // LED = 10Mbps link detect
+#define RPC_LED_FD (0x03) // LED = Full Duplex Mode
+#define RPC_LED_TX_RX (0x04) // LED = TX or RX packet occurred
+#define RPC_LED_100 (0x05) // LED = 100Mbps link dectect
+#define RPC_LED_TX (0x06) // LED = TX packet occurred
+#define RPC_LED_RX (0x07) // LED = RX packet occurred
+#define RPC_DEFAULT (RPC_ANEG | (RPC_LED_100 << RPC_LSXA_SHFT) | (RPC_LED_FD << RPC_LSXB_SHFT) | RPC_SPEED | RPC_DPLX)
+
/* BANK 1 */
#define CONFIG 0
#define CFG_AUI_SELECT 0x100
@@ -151,6 +169,13 @@ typedef unsigned long int dword;
#define MGMT 8
#define REVISION 10 /* ( hi: chip id low: rev # ) */
+// Management Interface Register (MII)
+#define MII_REG 0x0008
+#define MII_MSK_CRS100 0x4000 // Disables CRS100 detection during tx half dup
+#define MII_MDOE 0x0008 // MII Output Enable
+#define MII_MCLK 0x0004 // MII Clock, pin MDCLK
+#define MII_MDI 0x0002 // MII Input, pin MDI
+#define MII_MDO 0x0001 // MII Output, pin MDO
/* this is NOT on SMC9192 */
#define ERCV 12
@@ -186,6 +211,95 @@ typedef unsigned long int dword;
#define RS_ERRORS (RS_ALGNERR | RS_BADCRC | RS_TOOLONG | RS_TOOSHORT)
+// PHY Register Addresses (LAN91C111 Internal PHY)
+
+// PHY Control Register
+#define PHY_CNTL_REG 0x00
+#define PHY_CNTL_RST 0x8000 // 1=PHY Reset
+#define PHY_CNTL_LPBK 0x4000 // 1=PHY Loopback
+#define PHY_CNTL_SPEED 0x2000 // 1=100Mbps, 0=10Mpbs
+#define PHY_CNTL_ANEG_EN 0x1000 // 1=Enable Auto negotiation
+#define PHY_CNTL_PDN 0x0800 // 1=PHY Power Down mode
+#define PHY_CNTL_MII_DIS 0x0400 // 1=MII 4 bit interface disabled
+#define PHY_CNTL_ANEG_RST 0x0200 // 1=Reset Auto negotiate
+#define PHY_CNTL_DPLX 0x0100 // 1=Full Duplex, 0=Half Duplex
+#define PHY_CNTL_COLTST 0x0080 // 1= MII Colision Test
+
+// PHY Status Register
+#define PHY_STAT_REG 0x01
+#define PHY_STAT_CAP_T4 0x8000 // 1=100Base-T4 capable
+#define PHY_STAT_CAP_TXF 0x4000 // 1=100Base-X full duplex capable
+#define PHY_STAT_CAP_TXH 0x2000 // 1=100Base-X half duplex capable
+#define PHY_STAT_CAP_TF 0x1000 // 1=10Mbps full duplex capable
+#define PHY_STAT_CAP_TH 0x0800 // 1=10Mbps half duplex capable
+#define PHY_STAT_CAP_SUPR 0x0040 // 1=recv mgmt frames with not preamble
+#define PHY_STAT_ANEG_ACK 0x0020 // 1=ANEG has completed
+#define PHY_STAT_REM_FLT 0x0010 // 1=Remote Fault detected
+#define PHY_STAT_CAP_ANEG 0x0008 // 1=Auto negotiate capable
+#define PHY_STAT_LINK 0x0004 // 1=valid link
+#define PHY_STAT_JAB 0x0002 // 1=10Mbps jabber condition
+#define PHY_STAT_EXREG 0x0001 // 1=extended registers implemented
+
+// PHY Identifier Registers
+#define PHY_ID1_REG 0x02 // PHY Identifier 1
+#define PHY_ID2_REG 0x03 // PHY Identifier 2
+
+// PHY Auto-Negotiation Advertisement Register
+#define PHY_AD_REG 0x04
+#define PHY_AD_NP 0x8000 // 1=PHY requests exchange of Next Page
+#define PHY_AD_ACK 0x4000 // 1=got link code word from remote
+#define PHY_AD_RF 0x2000 // 1=advertise remote fault
+#define PHY_AD_T4 0x0200 // 1=PHY is capable of 100Base-T4
+#define PHY_AD_TX_FDX 0x0100 // 1=PHY is capable of 100Base-TX FDPLX
+#define PHY_AD_TX_HDX 0x0080 // 1=PHY is capable of 100Base-TX HDPLX
+#define PHY_AD_10_FDX 0x0040 // 1=PHY is capable of 10Base-T FDPLX
+#define PHY_AD_10_HDX 0x0020 // 1=PHY is capable of 10Base-T HDPLX
+#define PHY_AD_CSMA 0x0001 // 1=PHY is capable of 802.3 CMSA
+
+// PHY Auto-negotiation Remote End Capability Register
+#define PHY_RMT_REG 0x05
+// Uses same bit definitions as PHY_AD_REG
+
+// PHY Configuration Register 1
+#define PHY_CFG1_REG 0x10
+#define PHY_CFG1_LNKDIS 0x8000 // 1=Rx Link Detect Function disabled
+#define PHY_CFG1_XMTDIS 0x4000 // 1=TP Transmitter Disabled
+#define PHY_CFG1_XMTPDN 0x2000 // 1=TP Transmitter Powered Down
+#define PHY_CFG1_BYPSCR 0x0400 // 1=Bypass scrambler/descrambler
+#define PHY_CFG1_UNSCDS 0x0200 // 1=Unscramble Idle Reception Disable
+#define PHY_CFG1_EQLZR 0x0100 // 1=Rx Equalizer Disabled
+#define PHY_CFG1_CABLE 0x0080 // 1=STP(150ohm), 0=UTP(100ohm)
+#define PHY_CFG1_RLVL0 0x0040 // 1=Rx Squelch level reduced by 4.5db
+#define PHY_CFG1_TLVL_SHIFT 2 // Transmit Output Level Adjust
+#define PHY_CFG1_TLVL_MASK 0x003C
+#define PHY_CFG1_TRF_MASK 0x0003 // Transmitter Rise/Fall time
+
+
+// PHY Configuration Register 2
+#define PHY_CFG2_REG 0x11
+#define PHY_CFG2_APOLDIS 0x0020 // 1=Auto Polarity Correction disabled
+#define PHY_CFG2_JABDIS 0x0010 // 1=Jabber disabled
+#define PHY_CFG2_MREG 0x0008 // 1=Multiple register access (MII mgt)
+#define PHY_CFG2_INTMDIO 0x0004 // 1=Interrupt signaled with MDIO pulseo
+
+// PHY Status Output (and Interrupt status) Register
+#define PHY_INT_REG 0x12 // Status Output (Interrupt Status)
+#define PHY_INT_INT 0x8000 // 1=bits have changed since last read
+#define PHY_INT_LNKFAIL 0x4000 // 1=Link Not detected
+#define PHY_INT_LOSSSYNC 0x2000 // 1=Descrambler has lost sync
+#define PHY_INT_CWRD 0x1000 // 1=Invalid 4B5B code detected on rx
+#define PHY_INT_SSD 0x0800 // 1=No Start Of Stream detected on rx
+#define PHY_INT_ESD 0x0400 // 1=No End Of Stream detected on rx
+#define PHY_INT_RPOL 0x0200 // 1=Reverse Polarity detected
+#define PHY_INT_JAB 0x0100 // 1=Jabber detected
+#define PHY_INT_SPDDET 0x0080 // 1=100Base-TX mode, 0=10Base-T mode
+#define PHY_INT_DPLXDET 0x0040 // 1=Device in Full Duplex
+
+// PHY Interrupt/Status Mask Register
+#define PHY_MASK_REG 0x13 // Interrupt Mask
+// Uses the same bit definitions as PHY_INT_REG
+
+
/*-------------------------------------------------------------------------
* I define some macros to make it easier to do somewhat common
* or slightly complicated, repeated tasks.
diff --git a/src/drivers/net/sundance.c b/src/drivers/net/sundance.c
index 05621d4f2..701f922a4 100644
--- a/src/drivers/net/sundance.c
+++ b/src/drivers/net/sundance.c
@@ -52,13 +52,6 @@
#define drv_version "v1.12"
#define drv_date "2004-03-21"
-typedef unsigned char u8;
-typedef signed char s8;
-typedef unsigned short u16;
-typedef signed short s16;
-typedef unsigned int u32;
-typedef signed int s32;
-
#define HZ 100
/* Condensed operations for readability. */
diff --git a/src/drivers/net/tg3.c b/src/drivers/net/tg3.c
index 2d881f08a..ace2dfec6 100644
--- a/src/drivers/net/tg3.c
+++ b/src/drivers/net/tg3.c
@@ -9,6 +9,7 @@
/* 11-13-2003 timlegge Fix Issue with NetGear GA302T
* 11-18-2003 ebiederm Generalize NetGear Fix to what the code was supposed to be.
* 01-06-2005 Alf (Frederic Olivie) Add Dell bcm 5751 (0x1677) support
+ * 04-15-2005 Martin Vogt Add Fujitsu Siemens Computer (FSC) 0x1734 bcm 5751 0x105d support
*/
#include "etherboot.h"
@@ -2413,6 +2414,9 @@ static struct subsys_tbl_ent subsys_id_to_phy_id[] = {
{ PCI_VENDOR_ID_DELL, 0x0109, PHY_ID_BCM5411 }, /* MERLOT */
{ PCI_VENDOR_ID_DELL, 0x010a, PHY_ID_BCM5411 }, /* SLIM_MERLOT */
{ PCI_VENDOR_ID_DELL, 0x0179, PHY_ID_BCM5751 }, /* EtherXpress */
+
+ /* Fujitsu Siemens Computer */
+ { PCI_VENDOR_ID_FSC, 0x105d, PHY_ID_BCM5751 }, /* Futro C200 */
/* Compaq boards. */
{ PCI_VENDOR_ID_COMPAQ, 0x007c, PHY_ID_BCM5701 }, /* BANSHEE */
diff --git a/src/drivers/net/tg3.h b/src/drivers/net/tg3.h
index 6e05b9cc0..fd038f587 100644
--- a/src/drivers/net/tg3.h
+++ b/src/drivers/net/tg3.h
@@ -2156,7 +2156,7 @@ struct tg3 {
((X) == PHY_ID_BCM5400 || (X) == PHY_ID_BCM5401 || \
(X) == PHY_ID_BCM5411 || (X) == PHY_ID_BCM5701 || \
(X) == PHY_ID_BCM5703 || (X) == PHY_ID_BCM5704 || \
- (X) == PHY_ID_BCM5705 || (X) == PHY_ID_BCM5751 || \
+ (X) == PHY_ID_BCM5705 || (X) == PHY_ID_BCM5750 || (X) == PHY_ID_BCM5751 || \
(X) == PHY_ID_BCM8002 || (X) == PHY_ID_SERDES)
unsigned long regs;
diff --git a/src/drivers/net/tlan.h b/src/drivers/net/tlan.h
index e0379a7bc..de57d5984 100644
--- a/src/drivers/net/tlan.h
+++ b/src/drivers/net/tlan.h
@@ -34,22 +34,10 @@
* Indent Style: indent -kr -i8
***************************************************************************/
-/*
-#include <asm/io.h>
-#include <asm/types.h>
-#include <linux/netdevice.h>
-*/
-
-typedef unsigned char u8;
-typedef signed char s8;
-typedef unsigned short u16;
-typedef signed short s16;
-typedef unsigned int u32;
-typedef signed int s32;
- /*****************************************************************
- * TLan Definitions
- *
- ****************************************************************/
+/*****************************************************************
+* TLan Definitions
+*
+****************************************************************/
#define FALSE 0
#define TRUE 1
diff --git a/src/drivers/net/tulip.c b/src/drivers/net/tulip.c
index 28e38d952..864e32af6 100644
--- a/src/drivers/net/tulip.c
+++ b/src/drivers/net/tulip.c
@@ -48,6 +48,8 @@
/*********************************************************************/
/*
+ 08 Feb 2005 Ramesh Chander chhabaramesh at yahoo.co.in added table entries
+ for SGThomson STE10/100A
07 Sep 2003 timlegge Multicast Support Added
11 Apr 2001 mdc [patch to etherboot 4.7.24]
Major rewrite to include Linux tulip driver media detection
@@ -118,13 +120,6 @@ static int tulip_debug = 2; /* 1 normal messages, 0 quiet .. 7 verbo
#define TX_TIME_OUT 2*TICKS_PER_SEC
-typedef uint8_t u8;
-typedef int8_t s8;
-typedef uint16_t u16;
-typedef int16_t s16;
-typedef uint32_t u32;
-typedef int32_t s32;
-
/* helpful macros if on a big_endian machine for changing byte order.
not strictly needed on Intel */
#define get_unaligned(ptr) (*(ptr))
@@ -157,7 +152,7 @@ static const char * const medianame[32] = {
enum tulip_chips {
DC21040=0, DC21041=1, DC21140=2, DC21142=3, DC21143=3,
LC82C168, MX98713, MX98715, MX98725, AX88141, AX88140, PNIC2, COMET,
- COMPEX9881, I21145, XIRCOM
+ COMPEX9881, I21145, XIRCOM, SGThomson, /*Ramesh Chander*/
};
enum pci_id_flags_bits {
@@ -233,6 +228,8 @@ static const struct pci_id_info pci_id_tbl[] = {
TULIP_IOTYPE, 256, MX98715 },
{ "3Com 3cSOHO100B-TX (ADMtek Centuar)", { 0x930010b7, 0xffffffff, 0, 0, 0, 0 },
TULIP_IOTYPE, TULIP_SIZE, COMET },
+ { "SG Thomson STE10/100A", { 0x2774104a, 0xffffffff, 0, 0, 0, 0 },
+ TULIP_IOTYPE, 256, COMET }, /*Ramesh Chander*/
{ 0, { 0, 0, 0, 0, 0, 0 }, 0, 0, 0 },
};
@@ -268,6 +265,7 @@ static struct tulip_chip_table {
| HAS_PWRDWN | HAS_NWAY },
{ "Xircom tulip work-alike", HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII
| HAS_PWRDWN | HAS_NWAY },
+ { "SGThomson STE10/100A", HAS_MII | MC_HASH_ONLY }, /*Ramesh Chander*/
{ 0, 0 },
};
@@ -1705,6 +1703,8 @@ static void init_media(struct nic *nic)
outl(0x11000 | inw(ioaddr + 0xa0), ioaddr + 0xa0);
break;
case COMET:
+ /* Enable automatic Tx underrun recovery */
+ outl(inl(ioaddr + 0x88) | 1, ioaddr + 0x88);
tp->if_port = 0;
tp->csr6 = 0x00040000;
break;
@@ -2068,7 +2068,7 @@ PCI_ROM(0x125b, 0x1400, "ax88140", "ASIX AX88140"),
PCI_ROM(0x11f6, 0x9881, "rl100tx", "Compex RL100-TX"),
PCI_ROM(0x115d, 0x0003, "xircomtulip", "Xircom Tulip"),
PCI_ROM(0x104a, 0x0981, "tulip-0981", "Tulip 0x104a 0x0981"),
-PCI_ROM(0x104a, 0x2774, "tulip-2774", "Tulip 0x104a 0x2774"),
+PCI_ROM(0x104a, 0x2774, "SGThomson-STE10100A", "Tulip 0x104a 0x2774"), /*Modified by Ramesh Chander*/
PCI_ROM(0x1113, 0x9511, "tulip-9511", "Tulip 0x1113 0x9511"),
PCI_ROM(0x1186, 0x1561, "tulip-1561", "Tulip 0x1186 0x1561"),
PCI_ROM(0x1259, 0xa120, "tulip-a120", "Tulip 0x1259 0xa120"),
diff --git a/src/drivers/net/w89c840.c b/src/drivers/net/w89c840.c
index 1ed3503c8..c3f03f9f6 100644
--- a/src/drivers/net/w89c840.c
+++ b/src/drivers/net/w89c840.c
@@ -84,13 +84,6 @@
static const char *w89c840_version = "driver Version 0.94 - December 12, 2003";
-typedef unsigned char u8;
-typedef signed char s8;
-typedef unsigned short u16;
-typedef signed short s16;
-typedef unsigned int u32;
-typedef signed int s32;
-
/* Linux support functions */
#define virt_to_le32desc(addr) virt_to_bus(addr)
#define le32desc_to_virt(addr) bus_to_virt(addr)
diff --git a/src/include/background.h b/src/include/background.h
new file mode 100644
index 000000000..24cb3201f
--- /dev/null
+++ b/src/include/background.h
@@ -0,0 +1,52 @@
+#ifndef BACKGROUND_H
+#define BACKGROUND_H
+
+/** @file
+ *
+ * Background protocols
+ *
+ * Some protocols (e.g. ARP, IGMP) operate in the background; the
+ * upper layers are not aware of their operation. When an ARP query
+ * for the local station's IP address arrives, Etherboot must reply to
+ * it regardless of what other operations are currently in progress.
+ *
+ * Background protocols are called in two circumstances: when
+ * Etherboot is about to poll for a packet, and when Etherboot has
+ * received a packet that the upper layer (whatever that may currently
+ * be) isn't interested in.
+ *
+ */
+
+#include "tables.h"
+#include "ip.h"
+
+/** A background protocol */
+struct background {
+ /** Send method
+ *
+ * This method will be called whenever Etherboot is about to
+ * poll for a packet. The background protocol should use this
+ * method to send out any periodic transmissions that it may
+ * require.
+ */
+ void ( *send ) ( unsigned long timestamp );
+ /** Process method
+ *
+ * This method will be called whenever Etherboot has received
+ * a packet and doesn't know what to do with it.
+ */
+ void ( *process ) ( unsigned long timestamp, unsigned short ptype,
+ struct iphdr *ip );
+};
+
+/** A member of the background protocols table */
+#define __background __table ( background, 01 )
+
+/* Functions in background.c */
+
+extern void background_send ( unsigned long timestamp );
+
+extern void background_process ( unsigned long timestamp, unsigned short ptype,
+ struct iphdr *ip );
+
+#endif /* BACKGROUND_H */
diff --git a/src/include/buffer.h b/src/include/buffer.h
index 0085c7d16..ac4c31481 100644
--- a/src/include/buffer.h
+++ b/src/include/buffer.h
@@ -1,41 +1,93 @@
#ifndef BUFFER_H
#define BUFFER_H
+#include "compiler.h" /* for doxygen */
#include "stdint.h"
-/*
- * "start" and "end" denote the real boundaries of the buffer. "fill"
- * denotes the offset to the first free block in the buffer. (If the
- * buffer is full, "fill" will equal ( end - start ) ).
+/** @file
+ *
+ * Buffers for loading files.
+ *
+ * This file provides routines for filling a buffer with data received
+ * piecemeal, where the size of the data is not necessarily known in
+ * advance.
+ *
+ * Some protocols do not provide a mechanism for us to know the size
+ * of the file before we happen to receive a particular block
+ * (e.g. the final block in an MTFTP transfer). In addition, some
+ * protocols (all the multicast protocols plus any TCP-based protocol)
+ * can, in theory, provide the data in any order.
+ *
+ * Rather than requiring each protocol to implement its own equivalent
+ * of "dd" to arrange the data into well-sized pieces before handing
+ * off to the image loader, we provide these generic buffer functions
+ * which assemble a file into a single contiguous block. The whole
+ * block is then passed to the image loader.
+ *
+ * Example usage:
+ *
+ * @code
+ *
+ * struct buffer my_buffer;
+ * void *data;
+ * off_t offset;
+ * size_t len;
+ *
+ * // We have an area of memory [buf_start,buf_end) into which we want
+ * // to load a file, where buf_start and buf_end are physical addresses.
+ * buffer->start = buf_start;
+ * buffer->end = buf_end;
+ * init_buffer ( &buffer );
+ * ...
+ * while ( get_file_block ( ... ) ) {
+ * // Downloaded block is stored in [data,data+len), and represents
+ * // the portion of the file at offsets [offset,offset+len)
+ * if ( ! fill_buffer ( &buffer, data, offset, len ) ) {
+ * // An error occurred
+ * return 0;
+ * }
+ * ...
+ * }
+ * ...
+ * // The whole file is now present at [buf_start,buf_start+filesize),
+ * // where buf_start is a physical address. The struct buffer can simply
+ * // be discarded; there is no done_buffer() call.
+ *
+ * @endcode
+ *
+ * For a description of the internal operation, see buffer.c.
+ *
+ */
+
+/**
+ * A buffer
+ *
+ * #start and #end denote the real boundaries of the buffer, and are
+ * physical addresses. #fill denotes the offset to the first free
+ * block in the buffer. (If the buffer is full, #fill will equal
+ * #end-#start.)
*
*/
struct buffer {
- physaddr_t start;
- physaddr_t end;
- off_t fill;
+ physaddr_t start; /**< Start of buffer in memory */
+ physaddr_t end; /**< End of buffer in memory */
+ off_t fill; /**< Offset to first gap in buffer */
};
-/*
- * Free blocks in the buffer start with a "tail byte". If non-zero,
- * this byte indicates that the free block is the tail of the buffer,
- * i.e. occupies all the remaining space up to the end of the buffer.
- * When the tail byte is non-zero, it indicates that the remainder of
- * the descriptor (the struct buffer_free_block) follows the tail
- * byte.
+/**
+ * A free block descriptor.
*
- * This scheme is necessary because we may end up with a tail that is
- * smaller than a struct buffer_free_block.
+ * See buffer.c for a full description of the fields.
*
*/
struct buffer_free_block {
- char tail;
- physaddr_t next_free;
- physaddr_t end;
+ char tail; /**< Tail byte marker */
+ char reserved[3]; /**< Padding */
+ physaddr_t start; /**< Address of this free block */
+ physaddr_t next; /**< Address of next free block */
+ physaddr_t end; /**< End of this block */
} __attribute__ (( packed ));
-/* This must be provided by the architecture-dependent load_buffer.c */
-extern struct buffer load_buffer;
-
/* Functions in buffer.c */
extern void init_buffer ( struct buffer *buffer );
diff --git a/src/include/compiler.h b/src/include/compiler.h
index 4a7c48a1c..79781bc72 100644
--- a/src/include/compiler.h
+++ b/src/include/compiler.h
@@ -1,11 +1,30 @@
#ifndef COMPILER_H
#define COMPILER_H
-/* We export the symbol obj_OBJECT (OBJECT is defined on command-line)
- * as a global symbol, so that the linker can drag in selected object
- * files from the library using -u obj_OBJECT.
+/*
+ * Doxygen can't cope with some of the more esoteric areas of C, so we
+ * make its life simpler.
+ *
+ */
+#ifdef DOXYGEN
+#define __attribute__(x)
+#endif
+
+/** @file
+ *
+ * Global compiler definitions.
+ *
+ * This file is implicitly included by every @c .c file in Etherboot.
+ * It defines global macros such as DBG() and ASSERT().
*
- * Not quite sure why cpp requires two levels of macro call in order
+ * We arrange for each object to export the symbol @c obj_OBJECT
+ * (where @c OBJECT is the object name, e.g. @c rtl8139) as a global
+ * symbol, so that the linker can drag in selected object files from
+ * the library using <tt> -u obj_OBJECT </tt>.
+ *
+ */
+
+/* Not quite sure why cpp requires two levels of macro call in order
* to actually expand OBJECT...
*/
#undef _H1
@@ -30,7 +49,9 @@
__asm__ ( ".globl\t" OBJECT_SYMBOL_STR );
__asm__ ( ".equ\t" OBJECT_SYMBOL_STR ", 0" );
-/*
+/**
+ * Drag in an object by object name.
+ *
* Macro to allow objects to explicitly drag in other objects by
* object name. Used by config.c.
*
@@ -38,6 +59,56 @@ __asm__ ( ".equ\t" OBJECT_SYMBOL_STR ", 0" );
#define REQUIRE_OBJECT(object) \
__asm__ ( ".equ\tneed_" #object ", obj_" #object );
+/** @def DBG
+ *
+ * Print a debugging message.
+ *
+ * The debug level is set at build time by specifying the @c DEBUG=
+ * parameter on the @c make command line. For example, to enable
+ * debugging for the PCI bus functions (in pci.c) in a @c .dsk image
+ * for the @c rtl8139 card, you could use the command line
+ *
+ * @code
+ *
+ * make bin/rtl8139.dsk DEBUG=pci
+ *
+ * @endcode
+ *
+ * This will enable the debugging statements (DBG()) in pci.c. If
+ * debugging is not enabled, DBG() statements will be ignored.
+ *
+ * You can enable debugging in several objects simultaneously by
+ * separating them with commas, as in
+ *
+ * @code
+ *
+ * make bin/rtl8139.dsk DEBUG=pci,buffer,heap
+ *
+ * @endcode
+ *
+ * You can increase the debugging level for an object by specifying it
+ * with @c :N, where @c N is the level, as in
+ *
+ * @code
+ *
+ * make bin/rtl8139.dsk DEBUG=pci,buffer:2,heap
+ *
+ * @endcode
+ *
+ * which would enable debugging for the PCI, buffer-handling and
+ * heap-allocation code, with the buffer-handling code at level 2.
+ *
+ */
+
+/** @def DBG2
+ *
+ * Print a level 2 debugging message.
+ *
+ * As for DBG(). DBG2() takes effect only when the debugging level is
+ * 2 or greater.
+ *
+ */
+
/*
* If debug_OBJECT is set to a true value, the macro DBG(...) will
* expand to printf(...) when compiling OBJECT, and the symbol
@@ -67,8 +138,12 @@ __asm__ ( ".equ\tDEBUG_LEVEL, " DEBUG_SYMBOL_STR );
#define DBG2 DBG_PRINT
#endif
-/*
- * ASSERT() macros
+/**
+ * Assert a condition.
+ *
+ * If the condition is not true, a debug message will be printed.
+ * Assertions only take effect if the debug level is non-zero (see
+ * DBG()).
*
*/
#define ASSERT(x)
@@ -84,20 +159,35 @@ __asm__ ( ".equ\tDEBUG_LEVEL, " DEBUG_SYMBOL_STR );
} while (0)
#endif
-/*
- * Commonly-used attributes.
+/** Declare a data structure as packed. */
+#define PACKED __attribute__ (( packed ))
+
+/**
+ * Declare a variable or data structure as unused.
*
- * Note that __used can be used only for functions. If you have a
- * static variable declaration that you want to force to be included,
- * use __unused.
+ * Note that using #__unused on a static global variable (such as a
+ * table structure as mentioned in tables.h) is necessary in order to
+ * inhibit compiler warnings.
*
*/
-#define PACKED __attribute__ (( packed ))
#define __unused __attribute__ (( unused ))
+
+/**
+ * Declare a function as used.
+ *
+ * Necessary only if the function is called only from assembler code.
+ * You cannot use this attribute for static global variables; use
+ * #__unused instead.
+ *
+ */
#define __used __attribute__ (( used ))
+
+/** Declare a data structure to be aligned with 16-byte alignment */
#define __aligned __attribute__ (( aligned ( 16 ) ))
-/*
+/**
+ * Shared data.
+ *
* To save space in the binary when multiple-driver images are
* compiled, uninitialised data areas can be shared between drivers.
* This will typically be used to share statically-allocated receive
@@ -105,13 +195,16 @@ __asm__ ( ".equ\tDEBUG_LEVEL, " DEBUG_SYMBOL_STR );
*
* Use as e.g.
*
- * struct {
+ * @code
+ *
+ * struct {
* char rx_buf[NUM_RX_BUF][RX_BUF_SIZE];
* char tx_buf[TX_BUF_SIZE];
- * } my_static_data __shared;
+ * } my_static_data __shared;
+ *
+ * @endcode
*
*/
-
#define __shared __asm__ ( "_shared_bss" )
#endif /* ASSEMBLY */
diff --git a/src/include/console.h b/src/include/console.h
index 1decb9c3b..9e13293ae 100644
--- a/src/include/console.h
+++ b/src/include/console.h
@@ -5,19 +5,94 @@
#include "vsprintf.h"
#include "tables.h"
-/*
- * Consoles that cannot be used before their INIT_FN() has completed
- * should set disabled = 1 initially. This allows other console
- * devices to still be used to print out early debugging messages.
+/** @file
+ *
+ * User interaction.
+ *
+ * Various console devices can be selected via the build options
+ * CONSOLE_FIRMWARE, CONSOLE_SERIAL etc. The console functions
+ * putchar(), getchar() and iskey() delegate to the individual console
+ * drivers.
+ *
*/
+/**
+ * A console driver
+ *
+ * Defines the functions that implement a particular console type.
+ * Must be made part of the console drivers table by using
+ * #__console_driver.
+ *
+ * @note Consoles that cannot be used before their INIT_FN() has
+ * completed should set #disabled=1 initially. This allows other
+ * console devices to still be used to print out early debugging
+ * messages.
+ *
+ */
struct console_driver {
+ /** Console is disabled.
+ *
+ * The console's putchar(), getchar() and iskey() methods will
+ * not be called while #disabled==1. Typically the
+ * console's initialisation functions (called via INIT_FN())
+ * will set #disabled=0 upon completion.
+ *
+ */
int disabled;
+
+ /** Write a character to the console.
+ *
+ * @v character Character to be written
+ * @ret None -
+ * @err None -
+ *
+ */
void ( *putchar ) ( int character );
+
+ /** Read a character from the console.
+ *
+ * @v None -
+ * @ret character Character read
+ * @err None -
+ *
+ * If no character is available to be read, this method will
+ * block. The character read should not be echoed back to the
+ * console.
+ *
+ */
int ( *getchar ) ( void );
+
+ /** Check for available input.
+ *
+ * @v None -
+ * @ret True Input is available
+ * @ret False Input is not available
+ * @err None -
+ *
+ * This should return True if a subsequent call to getchar()
+ * will not block.
+ *
+ */
int ( *iskey ) ( void );
};
+/**
+ * Mark a <tt> struct console_driver </tt> as being part of the
+ * console drivers table.
+ *
+ * Use as e.g.
+ *
+ * @code
+ *
+ * struct console_driver my_console __console_driver = {
+ * .putchar = my_putchar,
+ * .getchar = my_getchar,
+ * .iskey = my_iskey,
+ * };
+ *
+ * @endcode
+ *
+ */
#define __console_driver __table ( console, 01 )
/* Function prototypes */
diff --git a/src/include/dns.h b/src/include/dns.h
index 5b8b81f13..33ee73fe5 100644
--- a/src/include/dns.h
+++ b/src/include/dns.h
@@ -70,12 +70,12 @@ struct dns_rr_info {
} __attribute__ (( packed ));
struct dns_rr_info_a {
- struct dns_rr_info;
+ struct dns_rr_info info;
struct in_addr in_addr;
} __attribute__ (( packed ));
struct dns_rr_info_cname {
- struct dns_rr_info;
+ struct dns_rr_info info;
char cname[0];
} __attribute__ (( packed ));
diff --git a/src/include/errno.h b/src/include/errno.h
new file mode 100644
index 000000000..e122d9c39
--- /dev/null
+++ b/src/include/errno.h
@@ -0,0 +1,141 @@
+#ifndef ERRNO_H
+#define ERRNO_H
+
+/** @file
+ *
+ * Error codes
+ *
+ */
+
+/* PXE error codes are determined by the PXE specification */
+
+/* Generic errors */
+#define PXENV_STATUS_SUCCESS 0x00
+#define PXENV_STATUS_FAILURE 0x01
+#define PXENV_STATUS_BAD_FUNC 0x02
+#define PXENV_STATUS_UNSUPPORTED 0x03
+#define PXENV_STATUS_KEEP_UNDI 0x04
+#define PXENV_STATUS_KEEP_ALL 0x05
+#define PXENV_STATUS_OUT_OF_RESOURCES 0x06
+
+/* ARP errors (0x10 to 0x1f) */
+#define PXENV_STATUS_ARP_TIMEOUT 0x11
+
+/* Base-Code state errors */
+#define PXENV_STATUS_UDP_CLOSED 0x18
+#define PXENV_STATUS_UDP_OPEN 0x19
+#define PXENV_STATUS_TFTP_CLOSED 0x1a
+#define PXENV_STATUS_TFTP_OPEN 0x1b
+
+/* BIOS/system errors (0x20 to 0x2f) */
+#define PXENV_STATUS_MCOPY_PROBLEM 0x20
+#define PXENV_STATUS_BIS_INTEGRITY_FAILURE 0x21
+#define PXENV_STATUS_BIS_VALIDATE_FAILURE 0x22
+#define PXENV_STATUS_BIS_INIT_FAILURE 0x23
+#define PXENV_STATUS_BIS_SHUTDOWN_FAILURE 0x24
+#define PXENV_STATUS_BIS_GBOA_FAILURE 0x25
+#define PXENV_STATUS_BIS_FREE_FAILURE 0x26
+#define PXENV_STATUS_BIS_GSI_FAILURE 0x27
+#define PXENV_STATUS_BIS_BAD_CKSUM 0x28
+
+/* TFTP/MTFTP errors (0x30 to 0x3f) */
+#define PXENV_STATUS_TFTP_CANNOT_ARP_ADDRESS 0x30
+#define PXENV_STATUS_TFTP_OPEN_TIMEOUT 0x32
+#define PXENV_STATUS_TFTP_UNKNOWN_OPCODE 0x33
+#define PXENV_STATUS_TFTP_READ_TIMEOUT 0x35
+#define PXENV_STATUS_TFTP_ERROR_OPCODE 0x36
+#define PXENV_STATUS_TFTP_CANNOT_OPEN_CONNECTION 0x38
+#define PXENV_STATUS_TFTP_CANNOT_READ_FROM_CONNECTION 0x39
+#define PXENV_STATUS_TFTP_TOO_MANY_PACKAGES 0x3a
+#define PXENV_STATUS_TFTP_FILE_NOT_FOUND 0x3b
+#define PXENV_STATUS_TFTP_ACCESS_VIOLATION 0x3c
+#define PXENV_STATUS_TFTP_NO_MCAST_ADDRESS 0x3d
+#define PXENV_STATUS_TFTP_NO_FILESIZE 0x3e
+#define PXENV_STATUS_TFTP_INVALID_PACKET_SIZE 0x3f
+
+/* Reserved errors 0x40 to 0x4f) */
+
+/* DHCP/BOOTP errors (0x50 to 0x5f) */
+#define PXENV_STATUS_DHCP_TIMEOUT 0x51
+#define PXENV_STATUS_DHCP_NO_IP_ADDRESS 0x52
+#define PXENV_STATUS_DHCP_NO_BOOTFILE_NAME 0x53
+#define PXENV_STATUS_DHCP_BAD_IP_ADDRESS 0x54
+
+/* Driver errors (0x60 to 0x6f) */
+#define PXENV_STATUS_UNDI_INVALID_FUNCTION 0x60
+#define PXENV_STATUS_UNDI_MEDIATEST_FAILED 0x61
+#define PXENV_STATUS_UNDI_CANNOT_INIT_NIC_FOR_MCAST 0x62
+#define PXENV_STATUS_UNDI_CANNOT_INITIALIZE_NIC 0x63
+#define PXENV_STATUS_UNDI_CANNOT_INITIALIZE_PHY 0x64
+#define PXENV_STATUS_UNDI_CANNOT_READ_CONFIG_DATA 0x65
+#define PXENV_STATUS_UNDI_CANNOT_READ_INIT_DATA 0x66
+#define PXENV_STATUS_UNDI_BAD_MAC_ADDRESS 0x67
+#define PXENV_STATUS_UNDI_BAD_EEPROM_CHECKSUM 0x68
+#define PXENV_STATUS_UNDI_ERROR_SETTING_ISR 0x69
+#define PXENV_STATUS_UNDI_INVALID_STATE 0x6a
+#define PXENV_STATUS_UNDI_TRANSMIT_ERROR 0x6b
+#define PXENV_STATUS_UNDI_INVALID_PARAMETER 0x6c
+
+/* ROM and NBP bootstrap errors (0x70 to 0x7f) */
+#define PXENV_STATUS_BSTRAP_PROMPT_MENU 0x74
+#define PXENV_STATUS_BSTRAP_MCAST_ADDR 0x76
+#define PXENV_STATUS_BSTRAP_MISSING_LIST 0x77
+#define PXENV_STATUS_BSTRAP_NO_RESPONSE 0x78
+#define PXENV_STATUS_BSTRAP_FILE_TOO_BIG 0x79
+
+/* Environment NBP errors (0x80 to 0x8f) */
+
+/* Reserved errors (0x90 to 0x9f) */
+
+/* Miscellaneous errors (0xa0 to 0xaf) */
+#define PXENV_STATUS_BINL_CANCELED_BY_KEYSTROKE 0xa0
+#define PXENV_STATUS_BINL_NO_PXE_SERVER 0xa1
+#define PXENV_STATUS_NOT_AVAILABLE_IN_PMODE 0xa2
+#define PXENV_STATUS_NOT_AVAILABLE_IN_RMODE 0xa3
+
+/* BUSD errors (0xb0 to 0xbf) */
+#define PXENV_STATUS_BUSD_DEVICE_NOT_SUPPORTED 0xb0
+
+/* Loader errors (0xc0 to 0xcf) */
+#define PXENV_STATUS_LOADER_NO_FREE_BASE_MEMORY 0xc0
+#define PXENV_STATUS_LOADER_NO_BC_ROMID 0xc1
+#define PXENV_STATUS_LOADER_BAD_BC_ROMID 0xc2
+#define PXENV_STATUS_LOADER_BAD_BC_RUNTIME_IMAGE 0xc3
+#define PXENV_STATUS_LOADER_NO_UNDI_ROMID 0xc4
+#define PXENV_STATUS_LOADER_BAD_UNDI_ROMID 0xc5
+#define PXENV_STATUS_LOADER_BAD_UNDI_DRIVER_IMAGE 0xc6
+#define PXENV_STATUS_LOADER_NO_PXE_STRUCT 0xc8
+#define PXENV_STATUS_LOADER_NO_PXENV_STRUCT 0xc9
+#define PXENV_STATUS_LOADER_UNDI_START 0xca
+#define PXENV_STATUS_LOADER_BC_START 0xcb
+
+/*
+ * The range 0xd0 to 0xff is defined as "Vendor errors" by the PXE
+ * spec. We place all our Etherboot-specific errors in this range.
+ * We also define some generic errors as aliases to the PXE errors.
+ *
+ */
+
+#define ENOERR 0x00
+#define ENOMEM PXENV_STATUS_OUT_OF_RESOURCES
+#define EBADIMG 0xd0
+#define EIMGRET 0xd1
+#define ETIMEDOUT 0xd2
+#define EINVAL 0xd3
+
+/* Data structures and declarations */
+
+#include "tables.h"
+
+extern int errno;
+
+extern const char * strerror ( int errno );
+
+struct errortab {
+ int errno;
+ const char *text;
+};
+
+#define __errortab __table(errortab,01)
+
+#endif /* ERRNO_H */
diff --git a/src/include/etherboot.h b/src/include/etherboot.h
index e61a711ff..b9546c043 100644
--- a/src/include/etherboot.h
+++ b/src/include/etherboot.h
@@ -1,6 +1,26 @@
#ifndef ETHERBOOT_H
#define ETHERBOOT_H
+/*
+ * Standard includes that we always want
+ *
+ */
+
+#include "compiler.h"
+#include "stddef.h"
+#include "stdint.h"
+
+
+/*
+ * IMPORTANT!!!!!!!!!!!!!!
+ *
+ * Everything below this point is cruft left over from older versions
+ * of Etherboot. Do not add *anything* below this point. Things are
+ * gradually being moved to individual header files.
+ *
+ */
+
+
#include <stdarg.h>
#include "osdep.h"
@@ -110,16 +130,11 @@ enum {
MAX_ARP
};
-#define IGMP_SERVER 0
-#define MAX_IGMP IGMP_SERVER+1
-
#define RARP_REQUEST 3
#define RARP_REPLY 4
#include "in.h"
-#define MULTICAST_MASK 0xF0000000
-#define MULTICAST_NETWORK 0xE0000000
/* Helper macros used to identify when DHCP options are valid/invalid in/outside of encapsulation */
#define NON_ENCAP_OPT in_encapsulated_options == 0 &&
@@ -134,7 +149,6 @@ enum {
#include "udp.h"
#include "tcp.h"
#include "bootp.h"
-#include "tftp.h"
#include "igmp.h"
#include "nfs.h"
#include "console.h"
@@ -145,12 +159,7 @@ struct arptable_t {
uint8_t node[6];
} PACKED;
-struct igmptable_t {
- in_addr group;
- unsigned long time;
-} PACKED;
-
-#define KERNEL_BUF (BOOTP_DATA_ADDR->bootp_reply.bp_file)
+#define KERNEL_BUF (bootp_data.bootp_reply.bp_file)
#define FLOPPY_BOOT_LOCATION 0x7c00
@@ -195,19 +204,13 @@ int tcp_reset(struct iphdr *ip);
typedef int (*reply_t)(int ival, void *ptr, unsigned short ptype, struct iphdr *ip, struct udphdr *udp, struct tcphdr *tcp);
extern int await_reply P((reply_t reply, int ival, void *ptr, long timeout));
extern int decode_rfc1533 P((unsigned char *, unsigned int, unsigned int, int));
-extern void join_group(int slot, unsigned long group);
-extern void leave_group(int slot);
#define RAND_MAX 2147483647L
extern uint16_t ipchksum P((const void *ip, unsigned long len));
extern uint16_t add_ipchksums P((unsigned long offset, uint16_t sum, uint16_t new));
extern int32_t random P((void));
extern long rfc2131_sleep_interval P((long base, int exp));
-extern long rfc1112_sleep_interval P((long base, int exp));
extern void cleanup P((void));
-/* config.c */
-extern void print_config(void);
-
/* osloader.c */
/* Be careful with sector_t it is an unsigned long long on x86 */
typedef uint64_t sector_t;
@@ -271,15 +274,6 @@ extern int elf_start(unsigned long machine, unsigned long entry, unsigned long p
extern unsigned long currticks P((void));
extern void exit P((int status));
-/* serial.c */
-extern int serial_getc P((void));
-extern void serial_putc P((int));
-extern int serial_ischar P((void));
-extern int serial_init P((void));
-extern void serial_fini P((void));
-
-/* floppy.c */
-extern int bootdisk P((int dev,int part));
/***************************************************************************
External variables
@@ -288,10 +282,11 @@ External variables
extern struct rom_info rom;
extern char *hostname;
extern int hostnamelen;
+extern unsigned char *addparam;
+extern int addparamlen;
extern jmp_buf restart_etherboot;
extern int url_port;
extern struct arptable_t arptable[MAX_ARP];
-extern struct igmptable_t igmptable[MAX_IGMP];
#ifdef IMAGE_MENU
extern int menutmo,menudefault;
extern unsigned char *defparams;
@@ -309,14 +304,6 @@ extern int freebsd_howto;
extern char freebsd_kernel_env[FREEBSD_KERNEL_ENV_SIZE];
#endif
-/* bootmenu.c */
-
-/* osloader.c */
-
-/* created by linker */
-extern char _virt_start[], _text[], _etext[], _text16[], _etext16[];
-extern char _data[], _edata[], _bss[], _ebss[], _end[];
-
/*
* Local variables:
diff --git a/src/include/igmp.h b/src/include/igmp.h
index 2235d6c66..48753eab5 100644
--- a/src/include/igmp.h
+++ b/src/include/igmp.h
@@ -1,5 +1,8 @@
-#ifndef _IGMP_H
-#define _IGMP_H
+#ifndef IGMP_H
+#define IGMP_H
+
+#include "stdint.h"
+#include "in.h"
#define IGMP_QUERY 0x11
#define IGMPv1_REPORT 0x12
@@ -7,11 +10,19 @@
#define IGMP_LEAVE 0x17
#define GROUP_ALL_HOSTS 0xe0000001 /* 224.0.0.1 Host byte order */
+#define MULTICAST_MASK 0xf0000000
+#define MULTICAST_NETWORK 0xe0000000
+
+enum {
+ IGMP_SERVER,
+ MAX_IGMP
+};
+
struct igmp {
- uint8_t type;
- uint8_t response_time;
- uint16_t chksum;
- in_addr group;
+ uint8_t type;
+ uint8_t response_time;
+ uint16_t chksum;
+ struct in_addr group;
} PACKED;
struct igmp_ip_t { /* Format of an igmp ip packet */
@@ -20,4 +31,12 @@ struct igmp_ip_t { /* Format of an igmp ip packet */
struct igmp igmp;
} PACKED;
-#endif /* _IGMP_H */
+struct igmptable_t {
+ struct in_addr group;
+ unsigned long time;
+} PACKED;
+
+extern void join_group ( int slot, unsigned long group );
+extern void leave_group ( int slot );
+
+#endif /* IGMP_H */
diff --git a/src/include/nmb.h b/src/include/nmb.h
index 695f8e08f..7948d9e48 100644
--- a/src/include/nmb.h
+++ b/src/include/nmb.h
@@ -14,7 +14,7 @@
#define NBNS_UDP_PORT 137
struct dns_rr_info_nb {
- struct dns_rr_info;
+ struct dns_rr_info info;
uint16_t nb_flags;
struct in_addr nb_address;
} __attribute__ (( packed ));
diff --git a/src/include/pci_ids.h b/src/include/pci_ids.h
index bcf4c3cd8..a853d4dcb 100644
--- a/src/include/pci_ids.h
+++ b/src/include/pci_ids.h
@@ -319,6 +319,7 @@
#define PCI_VENDOR_ID_MORETON 0x15aa
#define PCI_VENDOR_ID_ZOLTRIX 0x15b0
#define PCI_VENDOR_ID_PDC 0x15e9
+#define PCI_VENDOR_ID_FSC 0x1734
#define PCI_VENDOR_ID_SYMPHONY 0x1c1c
#define PCI_VENDOR_ID_TEKRAM 0x1de1
#define PCI_VENDOR_ID_3DLABS 0x3d3d
diff --git a/src/include/pxe.h b/src/include/pxe.h
index 48f555094..f8e2de79b 100644
--- a/src/include/pxe.h
+++ b/src/include/pxe.h
@@ -1,895 +1,59 @@
-/*
- * pxe.h for Etherboot.
- *
- * PXE is technically specified only for i386, but there's no reason
- * why we shouldn't make the API available for other architectures,
- * provided that someone wants to write the shim that allows an
- * external program to call pxe_api_call().
- *
- * We stick with Intel's data structure definitions as far as possible
- * on other architectures. Generally the only i386-specific stuff is
- * related to addressing: real-mode segment:offset addresses, segment
- * selectors, segment descriptors etc. We allow an architecture-
- * specific header to define these types, then build the PXE
- * structures. Note that we retain the names from the PXE
- * specification document (e.g. SEGOFF16_t) even if the architecture
- * in question doesn't represent a SEGOFF16_t as anything resembling a
- * 16-bit segment:offset address. This is done in order to keep the
- * structure definitions as close as possible to those in the spec, to
- * minimise confusion.
- *
- * This file derives from several originals. One is pxe.h from
- * FreeBSD. Another is general.h86 from netboot. The original
- * copyright notices are reproduced below. This entire file is
- * licensed under the GPL; the netboot code is GPL anyway and the
- * FreeBSD code allows us to relicense under the GPL provided that we
- * retain the FreeBSD copyright notice. This is my understanding,
- * anyway. Other portions are my own and therefore Copyright (C) 2004
- * Michael Brown <mbrown@fensystems.co.uk>.
- *
- * 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.
- */
-
#ifndef PXE_H
#define PXE_H
-/* Include architecture-specific PXE data types
- *
- * May define SEGOFF16_t, SEGDESC_t and SEGSEL_t. These should be
- * #defines to underlying * types. May also define
- * IS_NULL_SEGOFF16(segoff16), SEGOFF16_TO_PTR(segoff16) and
- * PTR_TO_SEGOFF16(ptr,segoff16)
- */
-#ifndef PXE_TYPES_H
-#include <pxe_types.h>
-#endif
-
-/* Defaults in case pxe_types.h did not define a type. These are
- * placeholder structures just to make the code compile.
- */
-#ifndef SEGOFF16_t
-#define SEGOFF16_t void*
-#endif
-
-#ifndef IS_NULL_SEGOFF16
-#define IS_NULL_SEGOFF16(segoff16) ( (segoff16) == NULL )
-#endif
-
-#ifndef SEGOFF16_TO_PTR
-#define SEGOFF16_TO_PTR(segoff16) (segoff16)
-#endif
-
-#ifndef PTR_TO_SEGOFF16
-#define PTR_TO_SEGOFF16(ptr,segoff16) (segoff16) = (ptr);
-#endif
-
-#ifndef SEGDESC_t
-#define SEGDESC_t void
-#endif
-
-#ifndef SEGSEL_t
-#define SEGSEL_t void
-#endif
-
-/*****************************************************************************
- * The following portion of this file is derived from FreeBSD's pxe.h.
- * Do not remove the copyright notice below.
- *****************************************************************************
- */
-
-/*
- * Copyright (c) 2000 Alfred Perlstein <alfred@freebsd.org>
- * All rights reserved.
- * Copyright (c) 2000 Paul Saab <ps@freebsd.org>
- * All rights reserved.
- * Copyright (c) 2000 John Baldwin <jhb@freebsd.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * $FreeBSD: src/sys/boot/i386/libi386/pxe.h,v 1.4.2.2 2000/09/10 02:52:18 ps Exp $
- */
-
-/*
- * The typedefs and structures declared in this file
- * clearly violate style(9), the reason for this is to conform to the
- * typedefs/structure-names used in the Intel literature to avoid confusion.
- *
- * It's for your own good. :)
- */
-
-/* It seems that intel didn't think about ABI,
- * either that or 16bit ABI != 32bit ABI (which seems reasonable)
- * I have to thank Intel for the hair loss I incurred trying to figure
- * out why PXE was mis-reading structures I was passing it (at least
- * from my point of view)
- *
- * Solution: use gcc's '__attribute__ ((packed))' to correctly align
- * structures passed into PXE
- * Question: does this really work for PXE's expected ABI?
- */
-#ifndef PACKED
-#define PACKED __attribute__ ((packed))
-#endif
-
-#define S_SIZE(s) s, sizeof(s) - 1
-
-#define IP_STR "%d.%d.%d.%d"
-#define IP_ARGS(ip) \
- (int)(ip >> 24) & 0xff, (int)(ip >> 16) & 0xff, \
- (int)(ip >> 8) & 0xff, (int)ip & 0xff
-
-#define MAC_STR "%02x:%02x:%02x:%02x:%02x:%02x"
-#define MAC_ARGS(mac) \
- mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]
-
-typedef uint16_t PXENV_EXIT_t;
-typedef uint16_t PXENV_STATUS_t;
-typedef uint32_t IP4_t;
-typedef uint32_t ADDR32_t;
-/* It seems as though UDP_PORT_t is in network order, although I can't
- * find anything in the spec to back this up. (Michael Brown)
- */
-typedef uint16_t UDP_PORT_t;
-
-#define MAC_ADDR_LEN 16
-typedef uint8_t MAC_ADDR[MAC_ADDR_LEN];
-
-/* PXENV+ */
-typedef struct {
- uint8_t Signature[6]; /* 'PXENV+' */
- uint16_t Version; /* MSB = major, LSB = minor */
- uint8_t Length; /* structure length */
- uint8_t Checksum; /* checksum pad */
- SEGOFF16_t RMEntry; /* SEG:OFF to PXE entry point */
- /* don't use PMOffset and PMSelector (from the 2.1 PXE manual) */
- uint32_t PMOffset; /* Protected mode entry */
- SEGSEL_t PMSelector; /* Protected mode selector */
- SEGSEL_t StackSeg; /* Stack segment address */
- uint16_t StackSize; /* Stack segment size (bytes) */
- SEGSEL_t BC_CodeSeg; /* BC Code segment address */
- uint16_t BC_CodeSize; /* BC Code segment size (bytes) */
- SEGSEL_t BC_DataSeg; /* BC Data segment address */
- uint16_t BC_DataSize; /* BC Data segment size (bytes) */
- SEGSEL_t UNDIDataSeg; /* UNDI Data segment address */
- uint16_t UNDIDataSize; /* UNDI Data segment size (bytes) */
- SEGSEL_t UNDICodeSeg; /* UNDI Code segment address */
- uint16_t UNDICodeSize; /* UNDI Code segment size (bytes) */
- SEGOFF16_t PXEPtr; /* SEG:OFF to !PXE struct,
- only present when Version > 2.1 */
-} PACKED pxenv_t;
-
-/* !PXE */
-typedef struct {
- uint8_t Signature[4];
- uint8_t StructLength;
- uint8_t StructCksum;
- uint8_t StructRev;
- uint8_t reserved_1;
- SEGOFF16_t UNDIROMID;
- SEGOFF16_t BaseROMID;
- SEGOFF16_t EntryPointSP;
- SEGOFF16_t EntryPointESP;
- SEGOFF16_t StatusCallout;
- uint8_t reserved_2;
- uint8_t SegDescCn;
- SEGSEL_t FirstSelector;
- SEGDESC_t Stack;
- SEGDESC_t UNDIData;
- SEGDESC_t UNDICode;
- SEGDESC_t UNDICodeWrite;
- SEGDESC_t BC_Data;
- SEGDESC_t BC_Code;
- SEGDESC_t BC_CodeWrite;
-} PACKED pxe_t;
-
-#define PXENV_START_UNDI 0x0000
-typedef struct {
- PXENV_STATUS_t Status;
- uint16_t ax;
- uint16_t bx;
- uint16_t dx;
- uint16_t di;
- uint16_t es;
-} PACKED t_PXENV_START_UNDI;
-
-#define PXENV_UNDI_STARTUP 0x0001
-typedef struct {
- PXENV_STATUS_t Status;
-} PACKED t_PXENV_UNDI_STARTUP;
-
-#define PXENV_UNDI_CLEANUP 0x0002
-typedef struct {
- PXENV_STATUS_t Status;
-} PACKED t_PXENV_UNDI_CLEANUP;
-
-#define PXENV_UNDI_INITIALIZE 0x0003
-typedef struct {
- PXENV_STATUS_t Status;
- ADDR32_t ProtocolIni; /* Phys addr of a copy of the driver module */
- uint8_t reserved[8];
-} PACKED t_PXENV_UNDI_INITIALIZE;
-
-
-#define MAXNUM_MCADDR 8
-typedef struct {
- uint16_t MCastAddrCount;
- MAC_ADDR McastAddr[MAXNUM_MCADDR];
-} PACKED t_PXENV_UNDI_MCAST_ADDRESS;
-
-#define PXENV_UNDI_RESET_ADAPTER 0x0004
-typedef struct {
- PXENV_STATUS_t Status;
- t_PXENV_UNDI_MCAST_ADDRESS R_Mcast_Buf;
-} PACKED t_PXENV_UNDI_RESET_ADAPTER;
-
-#define PXENV_UNDI_SHUTDOWN 0x0005
-typedef struct {
- PXENV_STATUS_t Status;
-} PACKED t_PXENV_UNDI_SHUTDOWN;
-
-#define PXENV_UNDI_OPEN 0x0006
-typedef struct {
- PXENV_STATUS_t Status;
- uint16_t OpenFlag;
- uint16_t PktFilter;
-# define FLTR_DIRECTED 0x0001
-# define FLTR_BRDCST 0x0002
-# define FLTR_PRMSCS 0x0003
-# define FLTR_SRC_RTG 0x0004
-
- t_PXENV_UNDI_MCAST_ADDRESS R_Mcast_Buf;
-} PACKED t_PXENV_UNDI_OPEN;
-
-#define PXENV_UNDI_CLOSE 0x0007
-typedef struct {
- PXENV_STATUS_t Status;
-} PACKED t_PXENV_UNDI_CLOSE;
-
-#define PXENV_UNDI_TRANSMIT 0x0008
-typedef struct {
- PXENV_STATUS_t Status;
- uint8_t Protocol;
-# define P_UNKNOWN 0
-# define P_IP 1
-# define P_ARP 2
-# define P_RARP 3
-
- uint8_t XmitFlag;
-# define XMT_DESTADDR 0x0000
-# define XMT_BROADCAST 0x0001
-
- SEGOFF16_t DestAddr;
- SEGOFF16_t TBD;
- uint32_t Reserved[2];
-} PACKED t_PXENV_UNDI_TRANSMIT;
-
-#define MAX_DATA_BLKS 8
-typedef struct {
- uint16_t ImmedLength;
- SEGOFF16_t Xmit;
- uint16_t DataBlkCount;
- struct DataBlk {
- uint8_t TDPtrType;
- uint8_t TDRsvdByte;
- uint16_t TDDataLen;
- SEGOFF16_t TDDataPtr;
- } DataBlock[MAX_DATA_BLKS];
-} PACKED t_PXENV_UNDI_TBD;
-
-#define PXENV_UNDI_SET_MCAST_ADDRESS 0x0009
-typedef struct {
- PXENV_STATUS_t Status;
- t_PXENV_UNDI_MCAST_ADDRESS R_Mcast_Buf;
-} PACKED t_PXENV_UNDI_SET_MCAST_ADDRESS;
-
-#define PXENV_UNDI_SET_STATION_ADDRESS 0x000A
-typedef struct {
- PXENV_STATUS_t Status;
- MAC_ADDR StationAddress; /* Temp MAC addres to use */
-} PACKED t_PXENV_UNDI_SET_STATION_ADDRESS;
-
-#define PXENV_UNDI_SET_PACKET_FILTER 0x000B
-typedef struct {
- PXENV_STATUS_t Status;
- uint8_t filter; /* see UNDI_OPEN (0x0006) */
-} PACKED t_PXENV_UNDI_SET_PACKET_FILTER;
-
-#define PXENV_UNDI_GET_INFORMATION 0x000C
-typedef struct {
- PXENV_STATUS_t Status;
- uint16_t BaseIo; /* Adapter base I/O address */
- uint16_t IntNumber; /* Adapter IRQ number */
- uint16_t MaxTranUnit; /* Adapter maximum transmit unit */
- uint16_t HwType; /* Type of protocol at the hardware addr */
-# define ETHER_TYPE 1
-# define EXP_ETHER_TYPE 2
-# define IEEE_TYPE 6
-# define ARCNET_TYPE 7
-
- uint16_t HwAddrLen; /* Length of hardware address */
- MAC_ADDR CurrentNodeAddress; /* Current hardware address */
- MAC_ADDR PermNodeAddress; /* Permanent hardware address */
- SEGSEL_t ROMAddress; /* Real mode ROM segment address */
- uint16_t RxBufCt; /* Receive queue length */
- uint16_t TxBufCt; /* Transmit queue length */
-} PACKED t_PXENV_UNDI_GET_INFORMATION;
-
-#define PXENV_UNDI_GET_STATISTICS 0x000D
-typedef struct {
- PXENV_STATUS_t Status;
- uint32_t XmitGoodFrames; /* Number of successful transmissions */
- uint32_t RcvGoodFrames; /* Number of good frames received */
- uint32_t RcvCRCErrors; /* Number of frames with CRC errors */
- uint32_t RcvResourceErrors; /* Number of frames dropped */
-} PACKED t_PXENV_UNDI_GET_STATISTICS;
-
-#define PXENV_UNDI_CLEAR_STATISTICS 0x000E
-typedef struct {
- PXENV_STATUS_t Status;
-} PACKED t_PXENV_UNDI_CLEAR_STATISTICS;
-
-#define PXENV_UNDI_INITIATE_DIAGS 0x000F
-typedef struct {
- PXENV_STATUS_t Status;
-} PACKED t_PXENV_UNDI_INITIATE_DIAGS;
-
-#define PXENV_UNDI_FORCE_INTERRUPT 0x0010
-typedef struct {
- PXENV_STATUS_t Status;
-} PACKED t_PXENV_UNDI_FORCE_INTERRUPT;
-
-#define PXENV_UNDI_GET_MCAST_ADDRESS 0x0011
-typedef struct {
- PXENV_STATUS_t Status;
- IP4_t InetAddr; /* IP mulicast address */
- MAC_ADDR MediaAddr; /* MAC multicast address */
-} PACKED t_PXENV_UNDI_GET_MCAST_ADDRESS;
-
-#define PXENV_UNDI_GET_NIC_TYPE 0x0012
-typedef struct {
- PXENV_STATUS_t Status;
- uint8_t NicType; /* Type of NIC */
-# define PCI_NIC 2
-# define PnP_NIC 3
-# define CardBus_NIC 4
-
- union {
- struct {
- uint16_t Vendor_ID;
- uint16_t Dev_ID;
- uint8_t Base_Class;
- uint8_t Sub_Class;
- uint8_t Prog_Intf;
- uint8_t Rev;
- uint16_t BusDevFunc;
- uint16_t SubVendor_ID;
- uint16_t SubDevice_ID;
- } pci, cardbus;
- struct {
- uint32_t EISA_Dev_ID;
- uint8_t Base_Class;
- uint8_t Sub_Class;
- uint8_t Prog_Intf;
- uint16_t CardSelNum;
- } pnp;
- } info;
-} PACKED t_PXENV_UNDI_GET_NIC_TYPE;
-
-#define PXENV_UNDI_GET_IFACE_INFO 0x0013
-typedef struct {
- PXENV_STATUS_t Status;
- uint8_t IfaceType[16]; /* Name of MAC type in ASCII. */
- uint32_t LinkSpeed; /* Defined in NDIS 2.0 spec */
- uint32_t ServiceFlags; /* Defined in NDIS 2.0 spec */
- uint32_t Reserved[4]; /* must be 0 */
-} PACKED t_PXENV_UNDI_GET_IFACE_INFO;
-
-#define PXENV_UNDI_ISR 0x0014
-typedef struct {
- PXENV_STATUS_t Status;
- uint16_t FuncFlag; /* PXENV_UNDI_ISR_OUT_xxx */
- uint16_t BufferLength; /* Length of Frame */
- uint16_t FrameLength; /* Total length of reciever frame */
- uint16_t FrameHeaderLength; /* Length of the media header in Frame */
- SEGOFF16_t Frame; /* receive buffer */
- uint8_t ProtType; /* Protocol type */
- uint8_t PktType; /* Packet Type */
-# define PXENV_UNDI_ISR_IN_START 1
-# define PXENV_UNDI_ISR_IN_PROCESS 2
-# define PXENV_UNDI_ISR_IN_GET_NEXT 3
-
- /* one of these will be returned for PXENV_UNDI_ISR_IN_START */
-# define PXENV_UNDI_ISR_OUT_OURS 0
-# define PXENV_UNDI_ISR_OUT_NOT_OURS 1
-
- /*
- * one of these will bre returnd for PXEND_UNDI_ISR_IN_PROCESS
- * and PXENV_UNDI_ISR_IN_GET_NEXT
- */
-# define PXENV_UNDI_ISR_OUT_DONE 0
-# define PXENV_UNDI_ISR_OUT_TRANSMIT 2
-# define PXENV_UNDI_ISR_OUT_RECEIVE 3
-# define PXENV_UNDI_ISR_OUT_BUSY 4
-} PACKED t_PXENV_UNDI_ISR;
-
-#define PXENV_STOP_UNDI 0x0015
-typedef struct {
- PXENV_STATUS_t Status;
-} PACKED t_PXENV_STOP_UNDI;
-
-#define PXENV_TFTP_OPEN 0x0020
-typedef struct {
- PXENV_STATUS_t Status;
- IP4_t ServerIPAddress;
- IP4_t GatewayIPAddress;
- uint8_t FileName[128];
- UDP_PORT_t TFTPPort;
- uint16_t PacketSize;
-} PACKED t_PXENV_TFTP_OPEN;
-
-#define PXENV_TFTP_CLOSE 0x0021
-typedef struct {
- PXENV_STATUS_t Status;
-} PACKED t_PXENV_TFTP_CLOSE;
-
-#define PXENV_TFTP_READ 0x0022
-typedef struct {
- PXENV_STATUS_t Status;
- uint16_t PacketNumber;
- uint16_t BufferSize;
- SEGOFF16_t Buffer;
-} PACKED t_PXENV_TFTP_READ;
-
-#define PXENV_TFTP_READ_FILE 0x0023
-typedef struct {
- PXENV_STATUS_t Status;
- uint8_t FileName[128];
- uint32_t BufferSize;
- ADDR32_t Buffer;
- IP4_t ServerIPAddress;
- IP4_t GatewayIPAdress;
- IP4_t McastIPAdress;
- UDP_PORT_t TFTPClntPort;
- UDP_PORT_t TFTPSrvPort;
- uint16_t TFTPOpenTimeOut;
- uint16_t TFTPReopenDelay;
-} PACKED t_PXENV_TFTP_READ_FILE;
-
-#define PXENV_TFTP_GET_FSIZE 0x0025
-typedef struct {
- PXENV_STATUS_t Status;
- IP4_t ServerIPAddress;
- IP4_t GatewayIPAdress;
- uint8_t FileName[128];
- uint32_t FileSize;
-} PACKED t_PXENV_TFTP_GET_FSIZE;
-
-#define PXENV_UDP_OPEN 0x0030
-typedef struct {
- PXENV_STATUS_t Status;
- IP4_t src_ip; /* IP address of this station */
-} PACKED t_PXENV_UDP_OPEN;
-
-#define PXENV_UDP_CLOSE 0x0031
-typedef struct {
- PXENV_STATUS_t Status;
-} PACKED t_PXENV_UDP_CLOSE;
-
-#define PXENV_UDP_READ 0x0032
-typedef struct {
- PXENV_STATUS_t Status;
- IP4_t src_ip; /* IP of sender */
- IP4_t dest_ip; /* Only accept packets sent to this IP */
- UDP_PORT_t s_port; /* UDP source port of sender */
- UDP_PORT_t d_port; /* Only accept packets sent to this port */
- uint16_t buffer_size; /* Size of the packet buffer */
- SEGOFF16_t buffer; /* SEG:OFF to the packet buffer */
-} PACKED t_PXENV_UDP_READ;
-
-#define PXENV_UDP_WRITE 0x0033
-typedef struct {
- PXENV_STATUS_t Status;
- IP4_t ip; /* dest ip addr */
- IP4_t gw; /* ip gateway */
- UDP_PORT_t src_port; /* source udp port */
- UDP_PORT_t dst_port; /* destination udp port */
- uint16_t buffer_size; /* Size of the packet buffer */
- SEGOFF16_t buffer; /* SEG:OFF to the packet buffer */
-} PACKED t_PXENV_UDP_WRITE;
-
-#define PXENV_UNLOAD_STACK 0x0070
-typedef struct {
- PXENV_STATUS_t Status;
- uint8_t reserved[10];
-} PACKED t_PXENV_UNLOAD_STACK;
-
-
-#define PXENV_GET_CACHED_INFO 0x0071
-typedef struct {
- PXENV_STATUS_t Status;
- uint16_t PacketType; /* type (defined right here) */
-# define PXENV_PACKET_TYPE_DHCP_DISCOVER 1
-# define PXENV_PACKET_TYPE_DHCP_ACK 2
-# define PXENV_PACKET_TYPE_BINL_REPLY 3
- uint16_t BufferSize; /* max to copy, leave at 0 for pointer */
- SEGOFF16_t Buffer; /* copy to, leave at 0 for pointer */
- uint16_t BufferLimit; /* max size of buffer in BC dataseg ? */
-} PACKED t_PXENV_GET_CACHED_INFO;
-
-
-/* structure filled in by PXENV_GET_CACHED_INFO
- * (how we determine which IP we downloaded the initial bootstrap from)
- * words can't describe...
- */
-typedef struct {
- uint8_t opcode;
-# define BOOTP_REQ 1
-# define BOOTP_REP 2
- uint8_t Hardware; /* hardware type */
- uint8_t Hardlen; /* hardware addr len */
- uint8_t Gatehops; /* zero it */
- uint32_t ident; /* random number chosen by client */
- uint16_t seconds; /* seconds since did initial bootstrap */
- uint16_t Flags; /* seconds since did initial bootstrap */
-# define BOOTP_BCAST 0x8000 /* ? */
- IP4_t cip; /* Client IP */
- IP4_t yip; /* Your IP */
- IP4_t sip; /* IP to use for next boot stage */
- IP4_t gip; /* Relay IP ? */
- MAC_ADDR CAddr; /* Client hardware address */
- uint8_t Sname[64]; /* Server's hostname (Optional) */
- uint8_t bootfile[128]; /* boot filename */
- union {
-# if 1
-# define BOOTP_DHCPVEND 1024 /* DHCP extended vendor field size */
-# else
-# define BOOTP_DHCPVEND 312 /* DHCP standard vendor field size */
-# endif
- uint8_t d[BOOTP_DHCPVEND]; /* raw array of vendor/dhcp options */
- struct {
- uint8_t magic[4]; /* DHCP magic cookie */
-# ifndef VM_RFC1048
-# define VM_RFC1048 0x63825363L /* ? */
-# endif
- uint32_t flags; /* bootp flags/opcodes */
- uint8_t pad[56]; /* I don't think intel knows what a
- union does... */
- } v;
- } vendor;
-} PACKED BOOTPLAYER;
-
-#define PXENV_RESTART_TFTP 0x0073
-#define t_PXENV_RESTART_TFTP t_PXENV_TFTP_READ_FILE
-
-#define PXENV_START_BASE 0x0075
-typedef struct {
- PXENV_STATUS_t Status;
-} PACKED t_PXENV_START_BASE;
-
-#define PXENV_STOP_BASE 0x0076
-typedef struct {
- PXENV_STATUS_t Status;
-} PACKED t_PXENV_STOP_BASE;
-
-/*****************************************************************************
- * The following portion of this file is derived from netboot's
- * general.h86. Do not remove the copyright notice below.
- *****************************************************************************
- */
-
-/*
- * general.h86 - Common PXE definitions
- *
- * Copyright (C) 2003 Gero Kuhlmann <gero@gkminix.han.de>
- *
- * 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.
- *
- * $Id$
- */
-
-/*
- **************************************************************************
- *
- * This file contains the Preboot API common definitions as
- * per Intels PXE specification version 2.0.
- *
- * Updated to comply with PXE specification version 2.1 by Michael Brown.
- *
- **************************************************************************
- *
- * Result codes returned in AX by a PXENV API service:
- */
-#define PXENV_EXIT_SUCCESS 0x0000
-#define PXENV_EXIT_FAILURE 0x0001
-
-
-
-/*
- **************************************************************************
- *
- * CPU types (defined in WfM 1.1):
- */
-#define PXENV_CPU_X86 0
-#define PXENV_CPU_ALPHA 1
-#define PXENV_CPU_PPC 2
-
-
-
-/*
- **************************************************************************
- *
- * Bus types (defined in WfM 1.1):
- */
-#define PXENV_BUS_ISA 0
-#define PXENV_BUS_EISA 1
-#define PXENV_BUS_MCA 2
-#define PXENV_BUS_PCI 3
-#define PXENV_BUS_VESA 4
-#define PXENV_BUS_PCMCIA 5
-
-
-
-/*
- **************************************************************************
- *
- * Status codes returned in the status word of the PXENV API parameter
- * structure. Some of these codes are also used to return status
- * information from a boot image loader back to the bootrom.
- */
-
-/* Generic API errors that are reported by the loader */
-#define PXENV_STATUS_SUCCESS 0x00
-#define PXENV_STATUS_FAILURE 0x01 /* general failure */
-#define PXENV_STATUS_BAD_FUNC 0x02 /* invalid function number */
-#define PXENV_STATUS_UNSUPPORTED 0x03 /* not yet supported */
-#define PXENV_STATUS_KEEP_UNDI 0x04 /* keep UNDI in memory */
-#define PXENV_STATUS_KEEP_ALL 0x05 /* keep everything in memory */
-#define PXENV_STATUS_OUT_OF_RESOURCES 0x06 /* also keep everything */
-
-/* ARP/UDP errors (0x10 to 0x1F) */
-#define PXENV_STATUS_ARP_CANCELED 0x10 /* ARP canceled by keystroke */
-#define PXENV_STATUS_ARP_TIMEOUT 0x11 /* ARP timeout */
-#define PXENV_STATUS_UDP_CLOSED 0x18 /* UDP closed */
-#define PXENV_STATUS_UDP_OPEN 0x19 /* UDP already open */
-#define PXENV_STATUS_TFTP_CLOSED 0x1A /* TFTP closed */
-#define PXENV_STATUS_TFTP_OPEN 0x1B /* TFTP already opened */
-
-/* BIOS/system errors (0x20 to 0x2F) */
-#define PXENV_STATUS_MCOPY_PROBLEM 0x20 /* can't copy into memory */
-
-/* TFP errors (0x30 to 0x3F) */
-#define PXENV_STATUS_TFTP_CANNOT_ARP 0x30 /* TFTP ARP problem */
-#define PXENV_STATUS_TFTP_OPEN_CANCELED 0x31 /* TFTP open canceled by key */
-#define PXENV_STATUS_TFTP_OPEN_TIMEOUT 0x32 /* timeout during TFTP open */
-#define PXENV_STATUS_TFTP_UNKNOWN_OPCODE 0x33 /* unknown TFTP opcode */
-#define PXENV_STATUS_TFTP_READ_CANCELED 0x34 /* TFTP read canceled by key */
-#define PXENV_STATUS_TFTP_READ_TIMEOUT 0x35 /* timeout during TFTP read */
-#define PXENV_STATUS_TFTP_ERROR_OPCODE 0x36 /* bad TFTP opcode */
-#define PXENV_STATUS_TFTP_CANNOT_OPEN_CONNECTION \
- 0x38 /* error during TFTP open */
-#define PXENV_STATUS_TFTP_CANNOT_READ_FROM_CONNECTION \
- 0x39 /* error during TFTP read */
-#define PXENV_STATUS_TFTP_TOO_MANY_PACKAGES \
- 0x3A /* too many packages */
-#define PXENV_STATUS_TFTP_FILE_NOT_FOUND 0x3B /* file not found */
-#define PXENV_STATUS_TFTP_ACCESS_VIOLATION 0x3C /* access violation */
-#define PXENV_STATUS_TFTP_NO_MCAST_ADDRESS 0x3D /* no multicast address */
-#define PXENV_STATUS_TFTP_NO_FILESIZE 0x3E /* unable to get file size */
-#define PXENV_STATUS_TFTP_INVALID_PACKET_SIZE \
- 0x3F /* invalid packet size */
-
-/* BOOTP errors (0x40 to 0x4F) */
-#define PXENV_STATUS_BOOTP_CANCELED 0x40 /* BOOTP canceled by key */
-#define PXENV_STATUS_BOOTP_TIMEOUT 0x41 /* timeout during BOOTP */
-#define PXENV_STATUS_BOOTP_NO_FILE 0x42 /* missing bootfile name */
-
-/* DHCP errors (0x50 to 0x5F) */
-#define PXENV_STATUS_DHCP_CANCELED 0x50 /* DHCP canceled by key */
-#define PXENV_STATUS_DHCP_TIMEOUT 0x51 /* timeout during DHCP */
-#define PXENV_STATUS_DHCP_NO_IP_ADDRESS 0x52 /* missing IP address */
-#define PXENV_STATUS_DHCP_NO_BOOTFILE_NAME 0x53 /* missing bootfile name */
-#define PXENV_STATUS_DHCP_BAD_IP_ADDRESS 0x54 /* invalid IP address */
-
-/* Driver errors (0x60 to 0x6F) */
-#define PXENV_STATUS_UNDI_INVALID_FUNCTION 0x60 /* invalid UNDI function */
-#define PXENV_STATUS_UNDI_MEDIATEST_FAILED 0x61 /* media test failed */
-#define PXENV_STATUS_UNDI_CANNOT_INIT_NIC_FOR_MCAST \
- 0x62 /* cannot init for multicast */
-#define PXENV_STATUS_UNDI_CANNOT_INITIALIZE_NIC \
- 0x63 /* cannot init NIC */
-#define PXENV_STATUS_UNDI_CANNOT_INITIALIZE_PHY \
- 0x64 /* cannot init hardware */
-#define PXENV_STATUS_UNDI_CANNOT_READ_CONFIG_DATA \
- 0x65 /* cannot read config data */
-#define PXENV_STATUS_UNDI_CANNOT_READ_INIT_DATA \
- 0x66 /* cannot read init data */
-#define PXENV_STATUS_UNDI_BAD_MAC_ADDRESS 0x67 /* invalid hardware address */
-#define PXENV_STATUS_UNDI_BAD_EEPROM_CHECKSUM \
- 0x68 /* invalid EEPROM checksum */
-#define PXENV_STATUS_UNDI_ERROR_SETTING_ISR 0x69
-#define PXENV_STATUS_UNDI_INVALID_STATE 0x6a /* invalid UNDI state */
-#define PXENV_STATUS_UNDI_TRANSMIT_ERROR 0x6b /* transmit error */
-#define PXENV_STATUS_UNDI_INVALID_PARAMETER \
- 0x6c /* almost anything */
-
-/* Bootstrap (.1) errors (0x70 to 0x7F) */
-#define PXENV_STATUS_BSTRAP_PROMPT_MENU 0x74 /* invalid bootstrap menu */
-#define PXENV_STATUS_BSTRAP_MCAST_ADDR 0x76 /* missing multicast address */
-#define PXENV_STATUS_BSTRAP_MISSING_LIST 0x77 /* missing file list */
-#define PXENV_STATUS_BSTRAP_NO_RESPONSE 0x78 /* no response from server */
-#define PXENV_STATUS_BSTRAP_FILE_TOO_BIG 0x79 /* next file too big */
-
-/* Environment (.2) errors (0x80 to 0x8F) */
-
-/* MTFTP errors (0x90 to 0x9F) */
-#define PXENV_STATUS_MTFTP_OPEN_CANCEL 0x91 /* MTFTP open canceled by key */
-#define PXENV_STATUS_MTFTP_OPEN_TIMEOUT 0x92 /* timeout during MTFTP open */
-#define PXENV_STATUS_MTFTP_UNKNOWN_OP 0x93 /* unknown TFTP opcode */
-#define PXENV_STATUS_MTFTP_READ_CANCEL 0x94 /* MTFTP read canceled by key */
-#define PXENV_STATUS_MTFTP_READ_TIMEOUT 0x95 /* timeout during MTFTP read */
-#define PXENV_STATUS_MTFTP_ERROR_OP 0x96 /* bad TFTP opcode */
-#define PXENV_STATUS_MTFTP_CANNOT_OPEN 0x98 /* error during MTFTP open */
-#define PXENV_STATUS_MTFTP_CANNOT_READ 0x99 /* error during MTFTP read */
-#define PXENV_STATUS_MTFTP_TOO_MANY 0x9A /* too many packages */
-#define PXENV_STATUS_MTFTP_PACK_SIZE 0x9B /* invalid package size */
-
-/* Misc. errors (0xA0 to 0xAF) */
-#define PXENV_STATUS_BINL_CANCELED_BY_KEYSTROKE \
- 0xA0 /* BINL canceled by key */
-#define PXENV_STATUS_BINL_NO_PXE_SERVER 0xA1 /* no BINL server found */
-#define PXENV_STATUS_NOT_AVAILABLE_IN_PMODE \
- 0xA2 /* not avail. in prot mode */
-#define PXENV_STATUS_NOT_AVAILABLE_IN_RMODE \
- 0xA3 /* not avail. in real mode */
-
-/* BUSD errors (0xB0 to 0xBF) */
-#define PXENV_STATUS_BUSD_DEVICE_NOT_SUPPORTED \
- 0xB0 /* BUSD services not enabled */
-#define PXENV_STATUS_BUSD_DEV_ENABLE 0xB1 /* BUSD device not enabled */
-
-/* Loader errors (0xC0 to 0xCF) */
-#define PXENV_STATUS_LOADER_NO_FREE_BASE_MEMORY \
- 0xC0 /* no free base memory */
-#define PXENV_STATUS_LOADER_NO_BC_ROMID 0xC1 /* no base code rom ID */
-#define PXENV_STATUS_LOADER_BAD_BC_ROMID 0xC2 /* bad base code rom ID */
-#define PXENV_STATUS_LOADER_BAD_BC_RUNTIME_IMAGE \
- 0xC3 /* bad base code image */
-#define PXENV_STATUS_LOADER_NO_UNDI_ROMID 0xC4 /* no UNDI rom ID */
-#define PXENV_STATUS_LOADER_BAD_UNDI_ROMID 0xC5 /* bad UNDI rom ID */
-#define PXENV_STATUS_LOADER_UNDI_DRIVER_IMAGE \
- 0xC6 /* bad UNDI runtime image */
-#define PXENV_STATUS_LOADER_NO_PXE_STRUCT 0xC8 /* missing !PXE struct */
-#define PXENV_STATUS_LOADER_NO_PXENV_STRUCT \
- 0xC9 /* missing PXENV+ struct */
-#define PXENV_STATUS_LOADER_UNDI_START 0xCA /* UNDI not started */
-#define PXENV_STATUS_LOADER_BC_START 0xCB /* base code not started */
-
-/* Reserved errors (0xD0 to 0xFF) */
-#define PXENV_STATUS_IMAGE_INVALID 0xD0 /* invalid boot image */
-#define PXENV_STATUS_STOP_BASE 0xD1 /* error stopping base code */
-#define PXENV_STATUS_UNLOAD_BASE 0xD2 /* error unloading base code */
-#define PXENV_STATUS_STOP_UNDI 0xD3 /* error stopping UNDI */
-#define PXENV_STATUS_CLEANUP_UNDI 0xD4 /* error cleaning up UNDI */
-
-
-/*****************************************************************************
- * The remainder of this file is original to Etherboot.
- *****************************************************************************
- */
-
-/* Dummy PXE opcode for the loader routine. We do this to make the
- * API simpler
- */
-#define PXENV_UNDI_LOADER 0x104d /* 'load' */
-
-typedef struct undi_loader {
- union {
- struct {
- PXENV_STATUS_t Status;
- uint16_t ax;
- uint16_t bx;
- uint16_t dx;
- uint16_t di;
- uint16_t es;
- };
- t_PXENV_START_UNDI start_undi;
- };
- uint16_t undi_ds;
- uint16_t undi_cs;
- SEGOFF16_t pxe_ptr;
- SEGOFF16_t pxenv_ptr;
-} PACKED undi_loader_t;
+#include "pxe_types.h"
+#include "pxe_api.h"
+#include "etherboot.h"
+#include "tftp.h"
/* Union used for PXE API calls; we don't know the type of the
* structure until we interpret the opcode. Also, Status is available
* in the same location for any opcode, and it's convenient to have
* non-specific access to it.
*/
-typedef union {
- PXENV_STATUS_t Status; /* Make it easy to read status
- for any operation */
- t_PXENV_START_UNDI start_undi;
- t_PXENV_UNDI_STARTUP undi_startup;
- t_PXENV_UNDI_CLEANUP undi_cleanup;
- t_PXENV_UNDI_INITIALIZE undi_initialize;
- t_PXENV_UNDI_RESET_ADAPTER undi_reset_adapter;
- t_PXENV_UNDI_SHUTDOWN undi_shutdown;
- t_PXENV_UNDI_OPEN undi_open;
- t_PXENV_UNDI_CLOSE undi_close;
- t_PXENV_UNDI_TRANSMIT undi_transmit;
- t_PXENV_UNDI_SET_MCAST_ADDRESS undi_set_mcast_address;
- t_PXENV_UNDI_SET_STATION_ADDRESS undi_set_station_address;
- t_PXENV_UNDI_SET_PACKET_FILTER undi_set_packet_filter;
- t_PXENV_UNDI_GET_INFORMATION undi_get_information;
- t_PXENV_UNDI_GET_STATISTICS undi_get_statistics;
- t_PXENV_UNDI_CLEAR_STATISTICS undi_clear_statistics;
- t_PXENV_UNDI_INITIATE_DIAGS undi_initiate_diags;
- t_PXENV_UNDI_FORCE_INTERRUPT undi_force_interrupt;
- t_PXENV_UNDI_GET_MCAST_ADDRESS undi_get_mcast_address;
- t_PXENV_UNDI_GET_NIC_TYPE undi_get_nic_type;
- t_PXENV_UNDI_GET_IFACE_INFO undi_get_iface_info;
- t_PXENV_UNDI_ISR undi_isr;
- t_PXENV_STOP_UNDI stop_undi;
- t_PXENV_TFTP_OPEN tftp_open;
- t_PXENV_TFTP_CLOSE tftp_close;
- t_PXENV_TFTP_READ tftp_read;
- t_PXENV_TFTP_READ_FILE tftp_read_file;
- t_PXENV_TFTP_GET_FSIZE tftp_get_fsize;
- t_PXENV_UDP_OPEN udp_open;
- t_PXENV_UDP_CLOSE udp_close;
- t_PXENV_UDP_READ udp_read;
- t_PXENV_UDP_WRITE udp_write;
- t_PXENV_UNLOAD_STACK unload_stack;
- t_PXENV_GET_CACHED_INFO get_cached_info;
- t_PXENV_RESTART_TFTP restart_tftp;
- t_PXENV_START_BASE start_base;
- t_PXENV_STOP_BASE stop_base;
- undi_loader_t loader;
-} t_PXENV_ANY;
+union u_PXENV_ANY {
+ /* Make it easy to read status for any operation */
+ PXENV_STATUS_t Status;
+ struct s_PXENV_UNLOAD_STACK unload_stack;
+ struct s_PXENV_GET_CACHED_INFO get_cached_info;
+ struct s_PXENV_TFTP_READ_FILE restart_tftp;
+ struct s_PXENV_START_UNDI start_undi;
+ struct s_PXENV_STOP_UNDI stop_undi;
+ struct s_PXENV_START_BASE start_base;
+ struct s_PXENV_STOP_BASE stop_base;
+ struct s_PXENV_TFTP_OPEN tftp_open;
+ struct s_PXENV_TFTP_CLOSE tftp_close;
+ struct s_PXENV_TFTP_READ tftp_read;
+ struct s_PXENV_TFTP_READ_FILE tftp_read_file;
+ struct s_PXENV_TFTP_GET_FSIZE tftp_get_fsize;
+ struct s_PXENV_UDP_OPEN udp_open;
+ struct s_PXENV_UDP_CLOSE udp_close;
+ struct s_PXENV_UDP_WRITE udp_write;
+ struct s_PXENV_UDP_READ udp_read;
+ struct s_PXENV_UNDI_STARTUP undi_startup;
+ struct s_PXENV_UNDI_CLEANUP undi_cleanup;
+ struct s_PXENV_UNDI_INITIALIZE undi_initialize;
+ struct s_PXENV_UNDI_RESET undi_reset_adapter;
+ struct s_PXENV_UNDI_SHUTDOWN undi_shutdown;
+ struct s_PXENV_UNDI_OPEN undi_open;
+ struct s_PXENV_UNDI_CLOSE undi_close;
+ struct s_PXENV_UNDI_TRANSMIT undi_transmit;
+ struct s_PXENV_UNDI_SET_MCAST_ADDRESS undi_set_mcast_address;
+ struct s_PXENV_UNDI_SET_STATION_ADDRESS undi_set_station_address;
+ struct s_PXENV_UNDI_SET_PACKET_FILTER undi_set_packet_filter;
+ struct s_PXENV_UNDI_GET_INFORMATION undi_get_information;
+ struct s_PXENV_UNDI_GET_STATISTICS undi_get_statistics;
+ struct s_PXENV_UNDI_CLEAR_STATISTICS undi_clear_statistics;
+ struct s_PXENV_UNDI_INITIATE_DIAGS undi_initiate_diags;
+ struct s_PXENV_UNDI_FORCE_INTERRUPT undi_force_interrupt;
+ struct s_PXENV_UNDI_GET_MCAST_ADDRESS undi_get_mcast_address;
+ struct s_PXENV_UNDI_GET_NIC_TYPE undi_get_nic_type;
+ struct s_PXENV_UNDI_GET_IFACE_INFO undi_get_iface_info;
+ struct s_PXENV_UNDI_GET_STATE undi_get_state;
+ struct s_PXENV_UNDI_ISR undi_isr;
+};
+
+typedef union u_PXENV_ANY PXENV_ANY_t;
/* PXE stack status indicator. See pxe_export.c for further
* explanation.
@@ -900,22 +64,32 @@ typedef enum {
READY
} pxe_stack_state_t;
+#define ENSURE_CAN_UNLOAD(structure) if ( ! ensure_pxe_state(CAN_UNLOAD) ) { \
+ structure->Status = PXENV_STATUS_UNDI_INVALID_STATE; \
+ return PXENV_EXIT_FAILURE; }
+#define ENSURE_MIDWAY(structure) if ( ! ensure_pxe_state(MIDWAY) ) { \
+ structure->Status = PXENV_STATUS_UNDI_INVALID_STATE; \
+ return PXENV_EXIT_FAILURE; }
+#define ENSURE_READY(structure) if ( ! ensure_pxe_state(READY) ) { \
+ structure->Status = PXENV_STATUS_UNDI_INVALID_STATE; \
+ return PXENV_EXIT_FAILURE; }
+
/* Data structures installed as part of a PXE stack. Architectures
* will have extra information to append to the end of this.
*/
#define PXE_TFTP_MAGIC_COOKIE ( ( 'P'<<24 ) | ( 'x'<<16 ) | ( 'T'<<8 ) | 'f' )
-typedef struct {
- pxe_t pxe __attribute__ ((aligned(16)));
- pxenv_t pxenv __attribute__ ((aligned(16)));
+typedef struct pxe_stack {
+ struct s_PXE pxe __attribute__ ((aligned(16)));
+ struct s_PXENV pxenv __attribute__ ((aligned(16)));
pxe_stack_state_t state;
union {
- BOOTPLAYER cached_info;
+ BOOTPLAYER_t cached_info;
char packet[ETH_FRAME_LEN];
struct {
uint32_t magic_cookie;
unsigned int len;
int eof;
- char data[TFTP_MAX_PACKET];
+ char data[TFTP_MAX_BLKSIZE];
} tftpdata;
struct {
char *buffer;
@@ -926,4 +100,10 @@ typedef struct {
struct {} arch_data __attribute__ ((aligned(16)));
} pxe_stack_t;
+extern int ensure_pxe_state ( pxe_stack_state_t wanted );
+
+extern pxe_stack_t *pxe_stack;
+
+extern PXENV_EXIT_t pxe_api_call ( int opcode, union u_PXENV_ANY *any );
+
#endif /* PXE_H */
diff --git a/src/include/pxe_api.h b/src/include/pxe_api.h
new file mode 100644
index 000000000..7256c57e5
--- /dev/null
+++ b/src/include/pxe_api.h
@@ -0,0 +1,1696 @@
+#ifndef PXE_API_H
+#define PXE_API_H
+
+/*
+ * 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.
+ */
+
+/** @file
+ *
+ * Preboot eXecution Environment (PXE) API
+ *
+ */
+
+#include "pxe_types.h"
+
+/** @addtogroup pxe Preboot eXecution Environment (PXE) API
+ * @{
+ */
+
+/** @defgroup pxe_api_call PXE entry points
+ *
+ * PXE entry points and calling conventions
+ *
+ * @{
+ */
+
+/** The PXENV+ structure */
+struct s_PXENV {
+ /** Signature
+ *
+ * Contains the bytes 'P', 'X', 'E', 'N', 'V', '+'.
+ */
+ UINT8_t Signature[6];
+ /** PXE API version
+ *
+ * MSB is major version number, LSB is minor version number.
+ * If the API version number is 0x0201 or greater, the !PXE
+ * structure pointed to by #PXEPtr should be used instead of
+ * this data structure.
+ */
+ UINT16_t Version;
+ UINT8_t Length; /**< Length of this structure */
+ /** Checksum
+ *
+ * The byte checksum of this structure (using the length in
+ * #Length) must be zero.
+ */
+ UINT8_t Checksum;
+ SEGOFF16_t RMEntry; /**< Real-mode PXENV+ entry point */
+ /** Protected-mode PXENV+ entry point offset
+ *
+ * PXE 2.1 deprecates this entry point. For protected-mode
+ * API calls, use the !PXE structure pointed to by #PXEPtr
+ * instead.
+ */
+ UINT32_t PMOffset;
+ /** Protected-mode PXENV+ entry point segment selector
+ *
+ * PXE 2.1 deprecates this entry point. For protected-mode
+ * API calls, use the !PXE structure pointed to by #PXEPtr
+ * instead.
+ */
+ SEGSEL_t PMSelector;
+ SEGSEL_t StackSeg; /**< Stack segment selector */
+ UINT16_t StackSize; /**< Stack segment size */
+ SEGSEL_t BC_CodeSeg; /**< Base-code code segment selector */
+ UINT16_t BC_CodeSize; /**< Base-code code segment size */
+ SEGSEL_t BC_DataSeg; /**< Base-code data segment selector */
+ UINT16_t BC_DataSize; /**< Base-code data segment size */
+ SEGSEL_t UNDIDataSeg; /**< UNDI data segment selector */
+ UINT16_t UNDIDataSize; /**< UNDI data segment size */
+ SEGSEL_t UNDICodeSeg; /**< UNDI code segment selector */
+ UINT16_t UNDICodeSize; /**< UNDI code segment size */
+ /** Address of the !PXE structure
+ *
+ * This field is present only if #Version is 0x0201 or
+ * greater. If present, it points to a struct s_PXE.
+ */
+ SEGOFF16_t PXEPtr;
+} PACKED;
+
+typedef struct s_PXENV PXENV_t;
+
+/** The !PXE structure */
+struct s_PXE {
+ /** Signature
+ *
+ * Contains the bytes '!', 'P', 'X', 'E'.
+ */
+ UINT8_t Signature[4];
+ UINT8_t StructLength; /**< Length of this structure */
+ /** Checksum
+ *
+ * The byte checksum of this structure (using the length in
+ * #StructLength) must be zero.
+ */
+ UINT8_t StructCksum;
+ /** Revision of this structure
+ *
+ * For PXE version 2.1, this field must be zero.
+ */
+ UINT8_t StructRev;
+ UINT8_t reserved_1; /**< Must be zero */
+ /** Address of the UNDI ROM ID structure
+ *
+ * This is a pointer to a struct s_UNDI_ROM_ID.
+ */
+ SEGOFF16_t UNDIROMID;
+ /** Address of the Base Code ROM ID structure
+ *
+ * This is a pointer to a struct s_BC_ROM_ID.
+ */
+ SEGOFF16_t BaseROMID;
+ /** 16-bit !PXE entry point
+ *
+ * This is the entry point for either real mode, or protected
+ * mode with a 16-bit stack segment.
+ */
+ SEGOFF16_t EntryPointSP;
+ /** 32-bit !PXE entry point
+ *
+ * This is the entry point for protected mode with a 32-bit
+ * stack segment.
+ */
+ SEGOFF16_t EntryPointESP;
+ /** Status call-out function
+ *
+ * @v 0 (if in a time-out loop)
+ * @v n Number of a received TFTP packet
+ * @ret 0 Continue operation
+ * @ret 1 Cancel operation
+ *
+ * This function will be called whenever the PXE stack is in
+ * protected mode, is waiting for an event (e.g. a DHCP reply)
+ * and wishes to allow the user to cancel the operation.
+ * Parameters are passed in register %ax; the return value
+ * must also be placed in register %ax. All other registers
+ * and flags @b must be preserved.
+ *
+ * In real mode, an internal function (that checks for a
+ * keypress) will be used.
+ *
+ * If this field is set to -1, no status call-out function
+ * will be used and consequently the user will not be allowed
+ * to interrupt operations.
+ *
+ * @note The PXE specification version 2.1 defines the
+ * StatusCallout field, mentions it 11 times, but nowhere
+ * defines what it actually does or how it gets called.
+ * Fortunately, the WfM specification version 1.1a deigns to
+ * inform us of such petty details.
+ */
+ SEGOFF16_t StatusCallout;
+ UINT8_t reserved_2; /**< Must be zero */
+ /** Number of segment descriptors
+ *
+ * If this number is greater than 7, the remaining descriptors
+ * follow immediately after #BC_CodeWrite.
+ */
+ UINT8_t SegDescCnt;
+ /** First protected-mode selector
+ *
+ * This is the segment selector value for the first segment
+ * assigned to PXE. Protected-mode selectors must be
+ * consecutive, according to the PXE 2.1 specification, though
+ * no reason is given. Each #SEGDESC_t includes a field for
+ * the segment selector, so this information is entirely
+ * redundant.
+ */
+ SEGSEL_t FirstSelector;
+ /** Stack segment descriptor */
+ SEGDESC_t Stack;
+ /** UNDI data segment descriptor */
+ SEGDESC_t UNDIData;
+ /** UNDI code segment descriptor */
+ SEGDESC_t UNDICode;
+ /** UNDI writable code segment descriptor */
+ SEGDESC_t UNDICodeWrite;
+ /** Base-code data segment descriptor */
+ SEGDESC_t BC_Data;
+ /** Base-code code segment descriptor */
+ SEGDESC_t BC_Code;
+ /** Base-code writable code segment descriptor */
+ SEGDESC_t BC_CodeWrite;
+} PACKED;
+
+typedef struct s_PXE PXE_t;
+
+/** @} */ /* pxe_api_call */
+
+/** @defgroup pxe_preboot_api PXE Preboot API
+ *
+ * General high-level functions: #PXENV_UNLOAD_STACK, #PXENV_START_UNDI etc.
+ *
+ * @{
+ */
+
+/** @defgroup pxenv_unload_stack PXENV_UNLOAD_STACK
+ *
+ * UNLOAD BASE CODE STACK
+ *
+ * @{
+ */
+
+/** PXE API function code for pxenv_unload_stack() */
+#define PXENV_UNLOAD_STACK 0x0070
+
+/** Parameter block for pxenv_unload_stack() */
+struct s_PXENV_UNLOAD_STACK {
+ PXENV_STATUS_t Status; /**< PXE status code */
+ UINT8_t reserved[10]; /**< Must be zero */
+} PACKED;
+
+typedef struct s_PXENV_UNLOAD_STACK PXENV_UNLOAD_STACK_t;
+
+extern PXENV_EXIT_t pxenv_unload_stack ( struct s_PXENV_UNLOAD_STACK
+ *unload_stack );
+
+/** @} */ /* pxenv_unload_stack */
+
+/** @defgroup pxenv_get_cached_info PXENV_GET_CACHED_INFO
+ *
+ * GET CACHED INFO
+ *
+ * @{
+ */
+
+/** PXE API function code for pxenv_get_cached_info() */
+#define PXENV_GET_CACHED_INFO 0x0071
+
+/** The client's DHCPDISCOVER packet */
+#define PXENV_PACKET_TYPE_DHCP_DISCOVER 1
+
+/** The DHCP server's DHCPACK packet */
+#define PXENV_PACKET_TYPE_DHCP_ACK 2
+
+/** The Boot Server's Discover Reply packet
+ *
+ * This packet contains DHCP option 60 set to "PXEClient", a valid
+ * boot file name, and may or may not contain MTFTP options.
+ */
+#define PXENV_PACKET_TYPE_CACHED_REPLY 3
+
+/** Parameter block for pxenv_get_cached_info() */
+struct s_PXENV_GET_CACHED_INFO {
+ PXENV_STATUS_t Status; /**< PXE status code */
+ /** Packet type.
+ *
+ * Valid values are #PXENV_PACKET_TYPE_DHCP_DISCOVER,
+ * #PXENV_PACKET_TYPE_DHCP_ACK or #PXENV_PACKET_TYPE_CACHED_REPLY
+ */
+ UINT16_t PacketType;
+ UINT16_t BufferSize; /**< Buffer size */
+ SEGOFF16_t Buffer; /**< Buffer address */
+ UINT16_t BufferLimit; /**< Maximum buffer size */
+} PACKED;
+
+typedef struct s_PXENV_GET_CACHED_INFO PXENV_GET_CACHED_INFO_t;
+
+#define BOOTP_REQ 1 /**< A BOOTP request packet */
+#define BOOTP_REP 2 /**< A BOOTP reply packet */
+
+/** DHCP broadcast flag
+ *
+ * Request a broadcast response (DHCPOFFER or DHCPACK) from the DHCP
+ * server.
+ */
+#define BOOTP_BCAST 0x8000
+
+#define VM_RFC1048 0x63825363L /**< DHCP magic cookie */
+
+/** Maximum length of DHCP options */
+#define BOOTP_DHCPVEND 1024
+
+/** Format of buffer filled in by pxenv_get_cached_info()
+ *
+ * This somewhat convoluted data structure simply describes the layout
+ * of a DHCP packet. Refer to RFC2131 section 2 for a full
+ * description.
+ */
+struct bootph {
+ /** Message opcode.
+ *
+ * Valid values are #BOOTP_REQ and #BOOTP_REP.
+ */
+ UINT8_t opcode;
+ /** NIC hardware type.
+ *
+ * Valid values are as for s_PXENV_UNDI_GET_INFORMATION::HwType.
+ */
+ UINT8_t Hardware;
+ UINT8_t Hardlen; /**< MAC address length */
+ /** Gateway hops
+ *
+ * Zero in packets sent by the client. May be non-zero in
+ * replies from the DHCP server, if the reply comes via a DHCP
+ * relay agent.
+ */
+ UINT8_t Gatehops;
+ UINT32_t ident; /**< DHCP transaction id (xid) */
+ /** Elapsed time
+ *
+ * Number of seconds since the client began the DHCP
+ * transaction.
+ */
+ UINT16_t seconds;
+ /** Flags
+ *
+ * This is the bitwise-OR of any of the following values:
+ * #BOOTP_BCAST.
+ */
+ UINT16_t Flags;
+ /** Client IP address
+ *
+ * Set only if the client already has an IP address.
+ */
+ IP4_t cip;
+ /** Your IP address
+ *
+ * This is the IP address that the server assigns to the
+ * client.
+ */
+ IP4_t yip;
+ /** Server IP address
+ *
+ * This is the IP address of the BOOTP/DHCP server.
+ */
+ IP4_t sip;
+ /** Gateway IP address
+ *
+ * This is the IP address of the BOOTP/DHCP relay agent, if
+ * any. It is @b not (necessarily) the address of the default
+ * gateway for routing purposes.
+ */
+ IP4_t gip;
+ MAC_ADDR_t CAddr; /**< Client MAC address */
+ UINT8_t Sname[64]; /**< Server host name */
+ UINT8_t bootfile[128]; /**< Boot file name */
+ /** DHCP options
+ *
+ * Don't ask. Just laugh. Then burn a copy of the PXE
+ * specification and send Intel an e-mail asking them if
+ * they've figured out what a "union" does in C yet.
+ */
+ union bootph_vendor {
+ UINT8_t d[BOOTP_DHCPVEND]; /**< DHCP options */
+ /** DHCP options */
+ struct bootph_vendor_v {
+ /** DHCP magic cookie
+ *
+ * Should have the value #VM_RFC1048.
+ */
+ UINT8_t magic[4];
+ UINT32_t flags; /**< BOOTP flags/opcodes */
+ /** "End of BOOTP vendor extensions"
+ *
+ * Abandon hope, all ye who consider the
+ * purpose of this field.
+ */
+ UINT8_t pad[56];
+ } v;
+ } vendor;
+} PACKED;
+
+typedef struct bootph BOOTPLAYER_t;
+
+extern PXENV_EXIT_t pxenv_get_cached_info ( struct s_PXENV_GET_CACHED_INFO
+ *get_cached_info );
+
+/** @} */ /* pxenv_get_cached_info */
+
+/** @defgroup pxenv_restart_tftp PXENV_RESTART_TFTP
+ *
+ * RESTART TFTP
+ *
+ * @{
+ */
+
+/** PXE API function code for pxenv_restart_tftp() */
+#define PXENV_RESTART_TFTP 0x0073
+
+/** Parameter block for pxenv_restart_tftp() */
+struct s_PXENV_TFTP_READ_FILE;
+
+typedef struct s_PXENV_RESTART_TFTP PXENV_RESTART_TFTP_t;
+
+extern PXENV_EXIT_t pxenv_restart_tftp ( struct s_PXENV_TFTP_READ_FILE
+ *restart_tftp );
+
+/** @} */ /* pxenv_restart_tftp */
+
+/** @defgroup pxenv_start_undi PXENV_START_UNDI
+ *
+ * START UNDI
+ *
+ * @{
+ */
+
+/** PXE API function code for pxenv_start_undi() */
+#define PXENV_START_UNDI 0x0000
+
+/** Parameter block for pxenv_start_undi() */
+struct s_PXENV_START_UNDI {
+ PXENV_STATUS_t Status; /**< PXE status code */
+ /** %ax register as passed to the Option ROM initialisation routine.
+ *
+ * For a PCI device, this should contain the bus:dev:fn value
+ * that uniquely identifies the PCI device in the system. For
+ * a non-PCI device, this field is not defined.
+ */
+ UINT16_t AX;
+ /** %bx register as passed to the Option ROM initialisation routine.
+ *
+ * For an ISAPnP device, this should contain the Card Select
+ * Number assigned to the ISAPnP card. For non-ISAPnP
+ * devices, this should contain 0xffff.
+ */
+ UINT16_t BX;
+ /** %dx register as passed to the Option ROM initialisation routine.
+ *
+ * For an ISAPnP device, this should contain the ISAPnP Read
+ * Port address as currently set in all ISAPnP cards. If
+ * there are no ISAPnP cards, this should contain 0xffff. (If
+ * this is a non-ISAPnP device, but there are ISAPnP cards in
+ * the system, this value is not well defined.)
+ */
+ UINT16_t DX;
+ /** %di register as passed to the Option ROM initialisation routine.
+ *
+ * This contains the #OFF16_t portion of a struct #s_SEGOFF16
+ * that points to the System BIOS Plug and Play Installation
+ * Check Structure. (Refer to section 4.4 of the Plug and
+ * Play BIOS specification for a description of this
+ * structure.)
+ *
+ * @note The PXE specification defines the type of this field
+ * as #UINT16_t. For x86, #OFF16_t and #UINT16_t are
+ * equivalent anyway; for other architectures #OFF16_t makes
+ * more sense.
+ */
+ OFF16_t DI;
+ /** %es register as passed to the Option ROM initialisation routine.
+ *
+ * This contains the #SEGSEL_t portion of a struct #s_SEGOFF16
+ * that points to the System BIOS Plug and Play Installation
+ * Check Structure. (Refer to section 4.4 of the Plug and
+ * Play BIOS specification for a description of this
+ * structure.)
+ *
+ * @note The PXE specification defines the type of this field
+ * as #UINT16_t. For x86, #SEGSEL_t and #UINT16_t are
+ * equivalent anyway; for other architectures #SEGSEL_t makes
+ * more sense.
+ */
+ SEGSEL_t ES;
+} PACKED;
+
+typedef struct s_PXENV_START_UNDI PXENV_START_UNDI_t;
+
+extern PXENV_EXIT_t pxenv_start_undi ( struct s_PXENV_START_UNDI *start_undi );
+
+/** @} */ /* pxenv_start_undi */
+
+/** @defgroup pxenv_stop_undi PXENV_STOP_UNDI
+ *
+ * STOP UNDI
+ *
+ * @{
+ */
+
+/** PXE API function code for pxenv_stop_undi() */
+#define PXENV_STOP_UNDI 0x0015
+
+/** Parameter block for pxenv_stop_undi() */
+struct s_PXENV_STOP_UNDI {
+ PXENV_STATUS_t Status; /**< PXE status code */
+} PACKED;
+
+typedef struct s_PXENV_STOP_UNDI PXENV_STOP_UNDI_t;
+
+extern PXENV_EXIT_t pxenv_stop_undi ( struct s_PXENV_STOP_UNDI *stop_undi );
+
+/** @} */ /* pxenv_stop_undi */
+
+/** @defgroup pxenv_start_base PXENV_START_BASE
+ *
+ * START BASE
+ *
+ * @{
+ */
+
+/** PXE API function code for pxenv_start_base() */
+#define PXENV_START_BASE 0x0075
+
+/** Parameter block for pxenv_start_base() */
+struct s_PXENV_START_BASE {
+ PXENV_STATUS_t Status; /**< PXE status code */
+} PACKED;
+
+typedef struct s_PXENV_START_BASE PXENV_START_BASE_t;
+
+extern PXENV_EXIT_t pxenv_start_base ( struct s_PXENV_START_BASE *start_base );
+
+/** @} */ /* pxenv_start_base */
+
+/** @defgroup pxenv_stop_base PXENV_STOP_BASE
+ *
+ * STOP BASE
+ *
+ * @{
+ */
+
+/** PXE API function code for pxenv_stop_base() */
+#define PXENV_STOP_BASE 0x0076
+
+/** Parameter block for pxenv_stop_base() */
+struct s_PXENV_STOP_BASE {
+ PXENV_STATUS_t Status; /**< PXE status code */
+} PACKED;
+
+typedef struct s_PXENV_STOP_BASE PXENV_STOP_BASE_t;
+
+extern PXENV_EXIT_t pxenv_stop_base ( struct s_PXENV_STOP_BASE *stop_base );
+
+/** @} */ /* pxenv_stop_base */
+
+/** @} */ /* pxe_preboot_api */
+
+/** @defgroup pxe_tftp_api PXE TFTP API
+ *
+ * Download files via TFTP or MTFTP
+ *
+ * @{
+ */
+
+/** @defgroup pxenv_tftp_open PXENV_TFTP_OPEN
+ *
+ * TFTP OPEN
+ *
+ * @{
+ */
+
+/** PXE API function code for pxenv_tftp_open() */
+#define PXENV_TFTP_OPEN 0x0020
+
+/** Parameter block for pxenv_tftp_open() */
+struct s_PXENV_TFTP_OPEN {
+ PXENV_STATUS_t Status; /**< PXE status code */
+ IP4_t ServerIPAddress; /**< TFTP server IP address */
+ IP4_t GatewayIPAddress; /**< Relay agent IP address */
+ UINT8_t FileName[128]; /**< File name */
+ UDP_PORT_t TFTPPort; /**< TFTP server UDP port */
+ /** Requested size of TFTP packets
+ *
+ * This is the TFTP "blksize" option. This must be at least
+ * 512, since servers that do not support TFTP options cannot
+ * negotiate blocksizes smaller than this.
+ */
+ UINT16_t PacketSize;
+} PACKED;
+
+typedef struct s_PXENV_TFTP_OPEN PXENV_TFTP_OPEN_t;
+
+extern PXENV_EXIT_t pxenv_tftp_open ( struct s_PXENV_TFTP_OPEN *tftp_open );
+
+/** @} */ /* pxenv_tftp_open */
+
+/** @defgroup pxenv_tftp_close PXENV_TFTP_CLOSE
+ *
+ * TFTP CLOSE
+ *
+ * @{
+ */
+
+/** PXE API function code for pxenv_tftp_close() */
+#define PXENV_TFTP_CLOSE 0x0021
+
+/** Parameter block for pxenv_tftp_close() */
+struct s_PXENV_TFTP_CLOSE {
+ PXENV_STATUS_t Status; /**< PXE status code */
+} PACKED;
+
+typedef struct s_PXENV_TFTP_CLOSE PXENV_TFTP_CLOSE_t;
+
+extern PXENV_EXIT_t pxenv_tftp_close ( struct s_PXENV_TFTP_CLOSE *tftp_close );
+
+/** @} */ /* pxenv_tftp_close */
+
+/** @defgroup pxenv_tftp_read PXENV_TFTP_READ
+ *
+ * TFTP READ
+ *
+ * @{
+ */
+
+/** PXE API function code for pxenv_tftp_read() */
+#define PXENV_TFTP_READ 0x0022
+
+/** Parameter block for pxenv_tftp_read() */
+struct s_PXENV_TFTP_READ {
+ PXENV_STATUS_t Status; /**< PXE status code */
+ UINT16_t PacketNumber; /**< TFTP packet number */
+ UINT16_t BufferSize; /**< Size of data buffer */
+ SEGOFF16_t Buffer; /**< Address of data buffer */
+} PACKED;
+
+typedef struct s_PXENV_TFTP_READ PXENV_TFTP_READ_t;
+
+extern PXENV_EXIT_t pxenv_tftp_read ( struct s_PXENV_TFTP_READ *tftp_read );
+
+/** @} */ /* pxenv_tftp_read */
+
+/** @defgroup pxenv_tftp_read_file PXENV_TFTP_READ_FILE
+ *
+ * TFTP/MTFTP READ FILE
+ *
+ * @{
+ */
+
+/** PXE API function code for pxenv_tftp_read_file() */
+#define PXENV_TFTP_READ_FILE 0x0023
+
+/** Parameter block for pxenv_tftp_read_file() */
+struct s_PXENV_TFTP_READ_FILE {
+ PXENV_STATUS_t Status; /**< PXE status code */
+ UINT8_t FileName[128]; /**< File name */
+ UINT32_t BufferSize; /**< Size of data buffer */
+ ADDR32_t Buffer; /**< Address of data buffer */
+ IP4_t ServerIPAddress; /**< TFTP server IP address */
+ IP4_t GatewayIPAddress; /**< Relay agent IP address */
+ /** File multicast IP address */
+ IP4_t McastIPAddress;
+ /** Client multicast listening port */
+ UDP_PORT_t TFTPClntPort;
+ /** Server multicast listening port */
+ UDP_PORT_t TFTPSrvPort;
+ /** TFTP open timeout.
+ *
+ * This is the timeout for receiving the first DATA or ACK
+ * packets during the MTFTP Listen phase.
+ */
+ UINT16_t TFTPOpenTimeOut;
+ /** TFTP reopen timeout.
+ *
+ * This is the timeout for receiving an ACK packet while in
+ * the MTFTP Listen phase (when at least one ACK packet has
+ * already been seen).
+ */
+ UINT16_t TFTPReopenDelay;
+} PACKED;
+
+typedef struct s_PXENV_TFTP_READ_FILE PXENV_TFTP_READ_FILE_t;
+
+extern PXENV_EXIT_t pxenv_tftp_read_file ( struct s_PXENV_TFTP_READ_FILE
+ *tftp_read_file );
+
+/** @} */ /* pxenv_tftp_read_file */
+
+/** @defgroup pxenv_tftp_get_fsize PXENV_TFTP_GET_FSIZE
+ *
+ * TFTP GET FILE SIZE
+ *
+ * @{
+ */
+
+/** PXE API function code for pxenv_tftp_get_fsize() */
+#define PXENV_TFTP_GET_FSIZE 0x0025
+
+/** Parameter block for pxenv_tftp_get_fsize() */
+struct s_PXENV_TFTP_GET_FSIZE {
+ PXENV_STATUS_t Status; /**< PXE status code */
+ IP4_t ServerIPAddress; /**< TFTP server IP address */
+ IP4_t GatewayIPAddress; /**< Relay agent IP address */
+ UINT8_t FileName[128]; /**< File name */
+ UINT32_t FileSize; /**< Size of the file */
+} PACKED;
+
+typedef struct s_PXENV_TFTP_GET_FSIZE PXENV_TFTP_GET_FSIZE_t;
+
+extern PXENV_EXIT_t pxenv_tftp_get_fsize ( struct s_PXENV_TFTP_GET_FSIZE
+ *get_fsize );
+
+/** @} */ /* pxenv_tftp_get_fsize */
+
+/** @} */ /* pxe_tftp_api */
+
+/** @defgroup pxe_udp_api PXE UDP API
+ *
+ * Transmit and receive UDP packets
+ *
+ * @{
+ */
+
+/** @defgroup pxenv_udp_open PXENV_UDP_OPEN
+ *
+ * UDP OPEN
+ *
+ * @{
+ */
+
+/** PXE API function code for pxenv_udp_open() */
+#define PXENV_UDP_OPEN 0x0030
+
+/** Parameter block for pxenv_udp_open() */
+struct s_PXENV_UDP_OPEN {
+ PXENV_STATUS_t Status; /**< PXE status code */
+ IP4_t src_ip; /**< IP address of this station */
+} PACKED;
+
+typedef struct s_PXENV_UDP_OPEN PXENV_UDP_OPEN_t;
+
+extern PXENV_EXIT_t pxenv_udp_open ( struct s_PXENV_UDP_OPEN *udp_open );
+
+/** @} */ /* pxenv_udp_open */
+
+/** @defgroup pxenv_udp_close PXENV_UDP_CLOSE
+ *
+ * UDP CLOSE
+ *
+ * @{
+ */
+
+/** PXE API function code for pxenv_udp_close() */
+#define PXENV_UDP_CLOSE 0x0031
+
+/** Parameter block for pxenv_udp_close() */
+struct s_PXENV_UDP_CLOSE {
+ PXENV_STATUS_t Status; /**< PXE status code */
+} PACKED;
+
+typedef struct s_PXENV_UDP_CLOSE PXENV_UDP_CLOSE_t;
+
+extern PXENV_EXIT_t pxenv_udp_close ( struct s_PXENV_UDP_CLOSE *udp_close );
+
+/** @} */ /* pxenv_udp_close */
+
+/** @defgroup pxenv_udp_write PXENV_UDP_WRITE
+ *
+ * UDP WRITE
+ *
+ * @{
+ */
+
+/** PXE API function code for pxenv_udp_write() */
+#define PXENV_UDP_WRITE 0x0033
+
+/** Parameter block for pxenv_udp_write() */
+struct s_PXENV_UDP_WRITE {
+ PXENV_STATUS_t Status; /**< PXE status code */
+ IP4_t ip; /**< Destination IP address */
+ IP4_t gw; /**< Relay agent IP address */
+ UDP_PORT_t src_port; /**< Source UDP port */
+ UDP_PORT_t dst_port; /**< Destination UDP port */
+ UINT16_t buffer_size; /**< UDP payload buffer size */
+ SEGOFF16_t buffer; /**< UDP payload buffer address */
+} PACKED;
+
+typedef struct s_PXENV_UDP_WRITE PXENV_UDP_WRITE_t;
+
+extern PXENV_EXIT_t pxenv_udp_write ( struct s_PXENV_UDP_WRITE *udp_write );
+
+/** @} */ /* pxenv_udp_write */
+
+/** @defgroup pxenv_udp_read PXENV_UDP_READ
+ *
+ * UDP READ
+ *
+ * @{
+ */
+
+/** PXE API function code for pxenv_udp_read() */
+#define PXENV_UDP_READ 0x0032
+
+/** Parameter block for pxenv_udp_read() */
+struct s_PXENV_UDP_READ {
+ PXENV_STATUS_t Status; /**< PXE status code */
+ IP4_t src_ip; /**< Source IP address */
+ IP4_t dest_ip; /**< Destination IP address */
+ UDP_PORT_t s_port; /**< Source UDP port */
+ UDP_PORT_t d_port; /**< Destination UDP port */
+ UINT16_t buffer_size; /**< UDP payload buffer size */
+ SEGOFF16_t buffer; /**< UDP payload buffer address */
+} PACKED;
+
+typedef struct s_PXENV_UDP_READ PXENV_UDP_READ_t;
+
+extern PXENV_EXIT_t pxenv_udp_read ( struct s_PXENV_UDP_READ *udp_read );
+
+/** @} */ /* pxenv_udp_read */
+
+/** @} */ /* pxe_udp_api */
+
+/** @defgroup pxe_undi_api PXE UNDI API
+ *
+ * Direct control of the network interface card
+ *
+ * @{
+ */
+
+/** @defgroup pxenv_undi_startup PXENV_UNDI_STARTUP
+ *
+ * UNDI STARTUP
+ *
+ * @{
+ */
+
+/** PXE API function code for pxenv_undi_startup() */
+#define PXENV_UNDI_STARTUP 0x0001
+
+#define PXENV_BUS_ISA 0 /**< ISA bus type */
+#define PXENV_BUS_EISA 1 /**< EISA bus type */
+#define PXENV_BUS_MCA 2 /**< MCA bus type */
+#define PXENV_BUS_PCI 3 /**< PCI bus type */
+#define PXENV_BUS_VESA 4 /**< VESA bus type */
+#define PXENV_BUS_PCMCIA 5 /**< PCMCIA bus type */
+
+/** Parameter block for pxenv_undi_startup() */
+struct s_PXENV_UNDI_STARTUP {
+ PXENV_STATUS_t Status; /**< PXE status code */
+} PACKED;
+
+typedef struct s_PXENV_UNDI_STARTUP PXENV_UNDI_STARTUP_t;
+
+extern PXENV_EXIT_t pxenv_undi_startup ( struct s_PXENV_UNDI_STARTUP
+ *undi_startup );
+
+/** @} */ /* pxenv_undi_startup */
+
+/** @defgroup pxenv_undi_cleanup PXENV_UNDI_CLEANUP
+ *
+ * UNDI CLEANUP
+ *
+ * @{
+ */
+
+/** PXE API function code for pxenv_undi_cleanup() */
+#define PXENV_UNDI_CLEANUP 0x0002
+
+/** Parameter block for pxenv_undi_cleanup() */
+struct s_PXENV_UNDI_CLEANUP {
+ PXENV_STATUS_t Status; /**< PXE status code */
+} PACKED;
+
+typedef struct s_PXENV_UNDI_CLEANUP PXENV_UNDI_CLEANUP_t;
+
+extern PXENV_EXIT_t pxenv_undi_cleanup ( struct s_PXENV_UNDI_CLEANUP
+ *undi_cleanup );
+
+/** @} */ /* pxenv_undi_cleanup */
+
+/** @defgroup pxenv_undi_initialize PXENV_UNDI_INITIALIZE
+ *
+ * UNDI INITIALIZE
+ *
+ * @{
+ */
+
+/** PXE API function code for pxenv_undi_initialize() */
+#define PXENV_UNDI_INITIALIZE 0x0003
+
+/** Parameter block for pxenv_undi_initialize() */
+struct s_PXENV_UNDI_INITIALIZE {
+ PXENV_STATUS_t Status; /**< PXE status code */
+ /** NDIS 2.0 configuration information, or NULL
+ *
+ * This is a pointer to the data structure returned by the
+ * NDIS 2.0 GetProtocolManagerInfo() API call. The data
+ * structure is documented, in a rather haphazard way, in
+ * section 4-17 of the NDIS 2.0 specification.
+ */
+ ADDR32_t ProtocolIni;
+ UINT8_t reserved[8]; /**< Must be zero */
+} PACKED;
+
+typedef struct s_PXENV_UNDI_INITIALIZE PXENV_UNDI_INITIALIZE_t;
+
+extern PXENV_EXIT_t pxenv_undi_initialize ( struct s_PXENV_UNDI_INITIALIZE
+ *undi_initialize );
+
+/** @} */ /* pxenv_undi_initialize */
+
+/** @defgroup pxenv_undi_reset_adapter PXENV_UNDI_RESET_ADAPTER
+ *
+ * UNDI RESET ADAPTER
+ *
+ * @{
+ */
+
+/** PXE API function code for pxenv_undi_reset_adapter() */
+#define PXENV_UNDI_RESET_ADAPTER 0x0004
+
+/** Maximum number of multicast MAC addresses */
+#define MAXNUM_MCADDR 8
+
+/** List of multicast MAC addresses */
+struct s_PXENV_UNDI_MCAST_ADDRESS {
+ /** Number of multicast MAC addresses */
+ UINT16_t MCastAddrCount;
+ /** List of up to #MAXNUM_MCADDR multicast MAC addresses */
+ MAC_ADDR_t McastAddr[MAXNUM_MCADDR];
+} PACKED;
+
+typedef struct s_PXENV_UNDI_MCAST_ADDRESS PXENV_UNDI_MCAST_ADDRESS_t;
+
+/** Parameter block for pxenv_undi_reset_adapter() */
+struct s_PXENV_UNDI_RESET {
+ PXENV_STATUS_t Status; /**< PXE status code */
+ /** Multicast MAC addresses */
+ struct s_PXENV_UNDI_MCAST_ADDRESS R_Mcast_Buf;
+} PACKED;
+
+typedef struct s_PXENV_UNDI_RESET PXENV_UNDI_RESET_t;
+
+extern PXENV_EXIT_t pxenv_undi_reset_adapter ( struct s_PXENV_UNDI_RESET
+ *undi_reset_adapter );
+
+/** @} */ /* pxenv_undi_reset_adapter */
+
+/** @defgroup pxenv_undi_shutdown PXENV_UNDI_SHUTDOWN
+ *
+ * UNDI SHUTDOWN
+ *
+ * @{
+ */
+
+/** PXE API function code for pxenv_undi_shutdown() */
+#define PXENV_UNDI_SHUTDOWN 0x0005
+
+/** Parameter block for pxenv_undi_shutdown() */
+struct s_PXENV_UNDI_SHUTDOWN {
+ PXENV_STATUS_t Status; /**< PXE status code */
+} PACKED;
+
+typedef struct s_PXENV_UNDI_SHUTDOWN PXENV_UNDI_SHUTDOWN_t;
+
+extern PXENV_EXIT_t pxenv_undi_shutdown ( struct s_PXENV_UNDI_SHUTDOWN
+ *undi_shutdown );
+
+/** @} */ /* pxenv_undi_shutdown */
+
+/** @defgroup pxenv_undi_open PXENV_UNDI_OPEN
+ *
+ * UNDI OPEN
+ *
+ * @{
+ */
+
+/** PXE API function code for pxenv_undi_open() */
+#define PXENV_UNDI_OPEN 0x0006
+
+/** Accept "directed" packets
+ *
+ * These are packets addresses to either this adapter's MAC address or
+ * to any of the configured multicast MAC addresses (see
+ * #s_PXENV_UNDI_MCAST_ADDRESS).
+ */
+#define FLTR_DIRECTED 0x0001
+/** Accept broadcast packets */
+#define FLTR_BRDCST 0x0002
+/** Accept all packets; listen in promiscuous mode */
+#define FLTR_PRMSCS 0x0004
+/** Accept source-routed packets */
+#define FLTR_SRC_RTG 0x0008
+
+/** Parameter block for pxenv_undi_open() */
+struct s_PXENV_UNDI_OPEN {
+ PXENV_STATUS_t Status; /**< PXE status code */
+ /** Open flags as defined in NDIS 2.0
+ *
+ * This is the OpenOptions field as passed to the NDIS 2.0
+ * OpenAdapter() API call. It is defined to be "adapter
+ * specific", though 0 is guaranteed to be a valid value.
+ */
+ UINT16_t OpenFlag;
+ /** Receive packet filter
+ *
+ * This is the bitwise-OR of any of the following flags:
+ * #FLTR_DIRECTED, #FLTR_BRDCST, #FLTR_PRMSCS and
+ * #FLTR_SRC_RTG.
+ */
+ UINT16_t PktFilter;
+ /** Multicast MAC addresses */
+ struct s_PXENV_UNDI_MCAST_ADDRESS R_Mcast_Buf;
+} PACKED;
+
+typedef struct s_PXENV_UNDI_OPEN PXENV_UNDI_OPEN_t;
+
+extern PXENV_EXIT_t pxenv_undi_open ( struct s_PXENV_UNDI_OPEN *undi_open );
+
+/** @} */ /* pxenv_undi_open */
+
+/** @defgroup pxenv_undi_close PXENV_UNDI_CLOSE
+ *
+ * UNDI CLOSE
+ *
+ * @{
+ */
+
+/** PXE API function code for pxenv_undi_close() */
+#define PXENV_UNDI_CLOSE 0x0007
+
+/** Parameter block for pxenv_undi_close() */
+struct s_PXENV_UNDI_CLOSE {
+ PXENV_STATUS_t Status; /**< PXE status code */
+} PACKED;
+
+typedef struct s_PXENV_UNDI_CLOSE PXENV_UNDI_CLOSE_t;
+
+extern PXENV_EXIT_t pxenv_undi_close ( struct s_PXENV_UNDI_CLOSE *undi_close );
+
+/** @} */ /* pxenv_undi_close */
+
+/** @defgroup pxenv_undi_transmit PXENV_UNDI_TRANSMIT
+ *
+ * UNDI TRANSMIT PACKET
+ *
+ * @{
+ */
+
+/** PXE API function code for pxenv_undi_transmit() */
+#define PXENV_UNDI_TRANSMIT 0x0008
+
+#define P_UNKNOWN 0 /**< Media header already filled in */
+#define P_IP 1 /**< IP protocol */
+#define P_ARP 2 /**< ARP protocol */
+#define P_RARP 3 /**< RARP protocol */
+#define P_OTHER 4 /**< Other protocol */
+
+#define XMT_DESTADDR 0x0000 /**< Unicast packet */
+#define XMT_BROADCAST 0x0001 /**< Broadcast packet */
+
+/** Maximum number of data blocks in a transmit buffer descriptor */
+#define MAX_DATA_BLKS 8
+
+/** A transmit buffer descriptor, as pointed to by s_PXENV_UNDI_TRANSMIT::TBD
+ */
+struct s_PXENV_UNDI_TBD {
+ UINT16_t ImmedLength; /**< Length of the transmit buffer */
+ SEGOFF16_t Xmit; /**< Address of the transmit buffer */
+ UINT16_t DataBlkCount;
+ /** Array of up to #MAX_DATA_BLKS additional transmit buffers */
+ struct DataBlk {
+ /** Always 1
+ *
+ * A value of 0 would indicate that #TDDataPtr were an
+ * #ADDR32_t rather than a #SEGOFF16_t. The PXE
+ * specification version 2.1 explicitly states that
+ * this is not supported; #TDDataPtr will always be a
+ * #SEGOFF16_t.
+ */
+ UINT8_t TDPtrType;
+ UINT8_t TDRsvdByte; /**< Must be zero */
+ UINT16_t TDDataLen; /**< Length of this transmit buffer */
+ SEGOFF16_t TDDataPtr; /**< Address of this transmit buffer */
+ } DataBlock[MAX_DATA_BLKS];
+} PACKED;
+
+typedef struct s_PXENV_UNDI_TBD PXENV_UNDI_TBD_t;
+
+/** Parameter block for pxenv_undi_transmit() */
+struct s_PXENV_UNDI_TRANSMIT {
+ PXENV_STATUS_t Status; /**< PXE status code */
+ /** Protocol
+ *
+ * Valid values are #P_UNKNOWN, #P_IP, #P_ARP or #P_RARP. If
+ * the caller has already filled in the media header, this
+ * field must be set to #P_UNKNOWN.
+ */
+ UINT8_t Protocol;
+ /** Unicast/broadcast flag
+ *
+ * Valid values are #XMT_DESTADDR or #XMT_BROADCAST.
+ */
+ UINT8_t XmitFlag;
+ SEGOFF16_t DestAddr; /**< Destination MAC address */
+ /** Address of the Transmit Buffer Descriptor
+ *
+ * This is a pointer to a struct s_PXENV_UNDI_TBD.
+ */
+ SEGOFF16_t TBD;
+ UINT32_t Reserved[2]; /**< Must be zero */
+} PACKED;
+
+typedef struct s_PXENV_UNDI_TRANSMIT PXENV_UNDI_TRANSMIT_t;
+
+extern PXENV_EXIT_t pxenv_undi_transmit ( struct s_PXENV_UNDI_TRANSMIT
+ *undi_transmit );
+
+/** @} */ /* pxenv_undi_transmit */
+
+/** @defgroup pxenv_undi_set_mcast_address PXENV_UNDI_SET_MCAST_ADDRESS
+ *
+ * UNDI SET MULTICAST ADDRESS
+ *
+ * @{
+ */
+
+/** PXE API function code for pxenv_undi_set_mcast_address() */
+#define PXENV_UNDI_SET_MCAST_ADDRESS 0x0009
+
+/** Parameter block for pxenv_undi_set_mcast_address() */
+struct s_PXENV_UNDI_SET_MCAST_ADDRESS {
+ PXENV_STATUS_t Status; /**< PXE status code */
+ /** List of multicast addresses */
+ struct s_PXENV_UNDI_MCAST_ADDRESS R_Mcast_Buf;
+} PACKED;
+
+typedef struct s_PXENV_UNDI_SET_MCAST_ADDRESS PXENV_UNDI_SET_MCAST_ADDRESS_t;
+
+extern PXENV_EXIT_t pxenv_undi_set_mcast_address (
+ struct s_PXENV_UNDI_SET_MCAST_ADDRESS *undi_set_mcast_address );
+
+/** @} */ /* pxenv_undi_set_mcast_address */
+
+/** @defgroup pxenv_undi_set_station_address PXENV_UNDI_SET_STATION_ADDRESS
+ *
+ * UNDI SET STATION ADDRESS
+ *
+ * @{
+ */
+
+/** PXE API function code for pxenv_undi_set_station_address() */
+#define PXENV_UNDI_SET_STATION_ADDRESS 0x000a
+
+/** Parameter block for pxenv_undi_set_station_address() */
+struct s_PXENV_UNDI_SET_STATION_ADDRESS {
+ PXENV_STATUS_t Status; /**< PXE status code */
+ MAC_ADDR_t StationAddress; /**< Station MAC address */
+} PACKED;
+
+typedef struct s_PXENV_UNDI_SET_STATION_ADDRESS PXENV_UNDI_SET_STATION_ADDRESS_t;
+
+extern PXENV_EXIT_t pxenv_undi_set_station_address (
+ struct s_PXENV_UNDI_SET_STATION_ADDRESS *undi_set_station_address );
+
+/** @} */ /* pxenv_undi_set_station_address */
+
+/** @defgroup pxenv_undi_set_packet_filter PXENV_UNDI_SET_PACKET_FILTER
+ *
+ * UNDI SET PACKET FILTER
+ *
+ * @{
+ */
+
+/** PXE API function code for pxenv_undi_set_packet_filter() */
+#define PXENV_UNDI_SET_PACKET_FILTER 0x000b
+
+/** Parameter block for pxenv_undi_set_packet_filter() */
+struct s_PXENV_UNDI_SET_PACKET_FILTER {
+ PXENV_STATUS_t Status; /**< PXE status code */
+ /** Receive packet filter
+ *
+ * This field takes the same values as
+ * s_PXENV_UNDI_OPEN::PktFilter.
+ *
+ * @note Yes, this field is a different size to
+ * s_PXENV_UNDI_OPEN::PktFilter. Blame "the managers at Intel
+ * who apparently let a consultant come up with the spec
+ * without any kind of adult supervision" (quote from hpa).
+ */
+ UINT8_t filter;
+} PACKED;
+
+typedef struct s_PXENV_UNDI_SET_PACKET_FILTER PXENV_UNDI_SET_PACKET_FILTER_t;
+
+extern PXENV_EXIT_t pxenv_undi_set_packet_filter (
+ struct s_PXENV_UNDI_SET_PACKET_FILTER *undi_set_packet_filter );
+
+/** @} */ /* pxenv_undi_set_packet_filter */
+
+/** @defgroup pxenv_undi_get_information PXENV_UNDI_GET_INFORMATION
+ *
+ * UNDI GET INFORMATION
+ *
+ * @{
+ */
+
+/** PXE API function code for pxenv_undi_get_information() */
+#define PXENV_UNDI_GET_INFORMATION 0x000c
+
+#define ETHER_TYPE 1 /**< Ethernet (10Mb) */
+#define EXP_ETHER_TYPE 2 /**< Experimental Ethernet (3Mb) */
+#define AX25_TYPE 3 /**< Amateur Radio AX.25 */
+#define TOKEN_RING_TYPE 4 /**< Proteon ProNET Token Ring */
+#define CHAOS_TYPE 5 /**< Chaos */
+#define IEEE_TYPE 6 /**< IEEE 802 Networks */
+#define ARCNET_TYPE 7 /**< ARCNET */
+
+/** Parameter block for pxenv_undi_get_information() */
+struct s_PXENV_UNDI_GET_INFORMATION {
+ PXENV_STATUS_t Status; /**< PXE status code */
+ UINT16_t BaseIo; /**< I/O base address */
+ UINT16_t IntNumber; /**< IRQ number */
+ UINT16_t MaxTranUnit; /**< Adapter MTU */
+ /** Hardware type
+ *
+ * Valid values are defined in RFC1010 ("Assigned numbers"),
+ * and are #ETHER_TYPE, #EXP_ETHER_TYPE, #AX25_TYPE,
+ * #TOKEN_RING_TYPE, #CHAOS_TYPE, #IEEE_TYPE or #ARCNET_TYPE.
+ */
+ UINT16_t HwType;
+ UINT16_t HwAddrLen; /**< MAC address length */
+ MAC_ADDR_t CurrentNodeAddress; /**< Current MAC address */
+ MAC_ADDR_t PermNodeAddress; /**< Permanent (EEPROM) MAC address */
+ SEGSEL_t ROMAddress; /**< Real-mode ROM segment address */
+ UINT16_t RxBufCt; /**< Receive queue length */
+ UINT16_t TxBufCt; /**< Transmit queue length */
+} PACKED;
+
+typedef struct s_PXENV_UNDI_GET_INFORMATION PXENV_UNDI_GET_INFORMATION_t;
+
+extern PXENV_EXIT_t pxenv_undi_get_information (
+ struct s_PXENV_UNDI_GET_INFORMATION *undi_get_information );
+
+/** @} */ /* pxenv_undi_get_information */
+
+/** @defgroup pxenv_undi_get_statistics PXENV_UNDI_GET_STATISTICS
+ *
+ * UNDI GET STATISTICS
+ *
+ * @{
+ */
+
+/** PXE API function code for pxenv_undi_get_statistics() */
+#define PXENV_UNDI_GET_STATISTICS 0x000d
+
+/** Parameter block for pxenv_undi_get_statistics() */
+struct s_PXENV_UNDI_GET_STATISTICS {
+ PXENV_STATUS_t Status; /**< PXE status code */
+ UINT32_t XmtGoodFrames; /**< Successful transmission count */
+ UINT32_t RcvGoodFrames; /**< Successful reception count */
+ UINT32_t RcvCRCErrors; /**< Receive CRC error count */
+ UINT32_t RcvResourceErrors; /**< Receive queue overflow count */
+} PACKED;
+
+typedef struct s_PXENV_UNDI_GET_STATISTICS PXENV_UNDI_GET_STATISTICS_t;
+
+extern PXENV_EXIT_t pxenv_undi_get_statistics (
+ struct s_PXENV_UNDI_GET_STATISTICS *undi_get_statistics );
+
+/** @} */ /* pxenv_undi_get_statistics */
+
+/** @defgroup pxenv_undi_clear_statistics PXENV_UNDI_CLEAR_STATISTICS
+ *
+ * UNDI CLEAR STATISTICS
+ *
+ * @{
+ */
+
+/** PXE API function code for pxenv_undi_clear_statistics() */
+#define PXENV_UNDI_CLEAR_STATISTICS 0x000e
+
+/** Parameter block for pxenv_undi_clear_statistics() */
+struct s_PXENV_UNDI_CLEAR_STATISTICS {
+ PXENV_STATUS_t Status; /**< PXE status code */
+} PACKED;
+
+typedef struct s_PXENV_UNDI_CLEAR_STATISTICS PXENV_UNDI_CLEAR_STATISTICS_t;
+
+extern PXENV_EXIT_t pxenv_undi_clear_statistics (
+ struct s_PXENV_UNDI_CLEAR_STATISTICS *undi_clear_statistics );
+
+/** @} */ /* pxenv_undi_clear_statistics */
+
+/** @defgroup pxenv_undi_initiate_diags PXENV_UNDI_INITIATE_DIAGS
+ *
+ * UNDI INITIATE DIAGS
+ *
+ * @{
+ */
+
+/** PXE API function code for pxenv_undi_initiate_diags() */
+#define PXENV_UNDI_INITIATE_DIAGS 0x000f
+
+/** Parameter block for pxenv_undi_initiate_diags() */
+struct s_PXENV_UNDI_INITIATE_DIAGS {
+ PXENV_STATUS_t Status; /**< PXE status code */
+} PACKED;
+
+typedef struct s_PXENV_UNDI_INITIATE_DIAGS PXENV_UNDI_INITIATE_DIAGS_t;
+
+extern PXENV_EXIT_t pxenv_undi_initiate_diags (
+ struct s_PXENV_UNDI_INITIATE_DIAGS *undi_initiate_diags );
+
+/** @} */ /* pxenv_undi_initiate_diags */
+
+/** @defgroup pxenv_undi_force_interrupt PXENV_UNDI_FORCE_INTERRUPT
+ *
+ * UNDI FORCE INTERRUPT
+ *
+ * @{
+ */
+
+/** PXE API function code for pxenv_undi_force_interrupt() */
+#define PXENV_UNDI_FORCE_INTERRUPT 0x0010
+
+/** Parameter block for pxenv_undi_force_interrupt() */
+struct s_PXENV_UNDI_FORCE_INTERRUPT {
+ PXENV_STATUS_t Status; /**< PXE status code */
+} PACKED;
+
+typedef struct s_PXENV_UNDI_FORCE_INTERRUPT PXENV_UNDI_FORCE_INTERRUPT_t;
+
+extern PXENV_EXIT_t pxenv_undi_force_interrupt (
+ struct s_PXENV_UNDI_FORCE_INTERRUPT *undi_force_interrupt );
+
+/** @} */ /* pxenv_undi_force_interrupt */
+
+/** @defgroup pxenv_undi_get_mcast_address PXENV_UNDI_GET_MCAST_ADDRESS
+ *
+ * UNDI GET MULTICAST ADDRESS
+ *
+ * @{
+ */
+
+/** PXE API function code for pxenv_undi_get_mcast_address() */
+#define PXENV_UNDI_GET_MCAST_ADDRESS 0x0011
+
+/** Parameter block for pxenv_undi_get_mcast_address() */
+struct s_PXENV_UNDI_GET_MCAST_ADDRESS {
+ PXENV_STATUS_t Status; /**< PXE status code */
+ IP4_t InetAddr; /**< Multicast IP address */
+ MAC_ADDR_t MediaAddr; /**< Multicast MAC address */
+} PACKED;
+
+typedef struct s_PXENV_UNDI_GET_MCAST_ADDRESS PXENV_UNDI_GET_MCAST_ADDRESS_t;
+
+extern PXENV_EXIT_t pxenv_undi_get_mcast_address (
+ struct s_PXENV_UNDI_GET_MCAST_ADDRESS *undi_get_mcast_address );
+
+/** @} */ /* pxenv_undi_get_mcast_address */
+
+/** @defgroup pxenv_undi_get_nic_type PXENV_UNDI_GET_NIC_TYPE
+ *
+ * UNDI GET NIC TYPE
+ *
+ * @{
+ */
+
+/** PXE API function code for pxenv_undi_get_nic_type() */
+#define PXENV_UNDI_GET_NIC_TYPE 0x0012
+
+#define PCI_NIC 2 /**< PCI network card */
+#define PnP_NIC 3 /**< ISAPnP network card */
+#define CardBus_NIC 4 /**< CardBus network card */
+
+/** Information for a PCI or equivalent NIC */
+struct pci_nic_info {
+ UINT16_t Vendor_ID; /**< PCI vendor ID */
+ UINT16_t Dev_ID; /**< PCI device ID */
+ UINT8_t Base_Class; /**< PCI base class */
+ UINT8_t Sub_Class; /**< PCI sub class */
+ UINT8_t Prog_Intf; /**< PCI programming interface */
+ UINT8_t Rev; /**< PCI revision */
+ UINT16_t BusDevFunc; /**< PCI bus:dev:fn address */
+ UINT16_t SubVendor_ID; /**< PCI subvendor ID */
+ UINT16_t SubDevice_ID; /**< PCI subdevice ID */
+} PACKED;
+
+/** Information for an ISAPnP or equivalent NIC */
+struct pnp_nic_info {
+ UINT32_t EISA_Dev_ID; /**< EISA device ID */
+ UINT8_t Base_Class; /**< Base class */
+ UINT8_t Sub_Class; /**< Sub class */
+ UINT8_t Prog_Intf; /**< Programming interface */
+ /** Card Select Number assigned to card */
+ UINT16_t CardSelNum;
+} PACKED;
+
+/** Parameter block for pxenv_undi_get_nic_type() */
+struct s_PXENV_UNDI_GET_NIC_TYPE {
+ PXENV_STATUS_t Status; /**< PXE status code */
+ /** NIC type
+ *
+ * Valid values are #PCI_NIC, #PnP_NIC or #CardBus_NIC.
+ */
+ UINT8_t NicType;
+ /** NIC information */
+ union nic_type_info {
+ /** NIC information (if #NicType==#PCI_NIC) */
+ struct pci_nic_info pci;
+ /** NIC information (if #NicType==#CardBus_NIC) */
+ struct pci_nic_info cardbus;
+ /** NIC information (if #NicType==#PnP_NIC) */
+ struct pnp_nic_info pnp;
+ } info;
+} PACKED;
+
+typedef struct s_PXENV_UNDI_GET_NIC_TYPE PXENV_UNDI_GET_NIC_TYPE_t;
+
+extern PXENV_EXIT_t pxenv_undi_get_nic_type (
+ struct s_PXENV_UNDI_GET_NIC_TYPE *undi_get_nic_type );
+
+/** @} */ /* pxenv_undi_get_nic_type */
+
+/** @defgroup pxenv_undi_get_iface_info PXENV_UNDI_GET_IFACE_INFO
+ *
+ * UNDI GET IFACE INFO
+ *
+ * @{
+ */
+
+/** PXE API function code for pxenv_undi_get_iface_info() */
+#define PXENV_UNDI_GET_IFACE_INFO 0x0013
+
+/** Parameter block for pxenv_undi_get_iface_info() */
+struct s_PXENV_UNDI_GET_IFACE_INFO {
+ PXENV_STATUS_t Status; /**< PXE status code */
+ /** Interface type
+ *
+ * This is defined in the NDIS 2.0 specification to be one of
+ * the strings "802.3", "802.4", "802.5", "802.6", "DIX",
+ * "DIX+802.3", "APPLETALK", "ARCNET", "FDDI", "SDLC", "BSC",
+ * "HDLC", or "ISDN".
+ *
+ * "Normal" Ethernet, for various historical reasons, is
+ * "DIX+802.3".
+ */
+ UINT8_t IfaceType[16];
+ UINT32_t LinkSpeed; /**< Link speed, in bits per second */
+ /** Service flags
+ *
+ * These are the "service flags" defined in the "MAC
+ * Service-Specific Characteristics" table in the NDIS 2.0
+ * specification. Almost all of them are irrelevant to PXE.
+ */
+ UINT32_t ServiceFlags;
+ UINT32_t Reserved[4]; /**< Must be zero */
+} PACKED;
+
+typedef struct s_PXENV_UNDI_GET_IFACE_INFO PXENV_UNDI_GET_IFACE_INFO_t;
+
+extern PXENV_EXIT_t pxenv_undi_get_iface_info (
+ struct s_PXENV_UNDI_GET_IFACE_INFO *undi_get_iface_info );
+
+/** @} */ /* pxenv_undi_get_iface_info */
+
+/** @defgroup pxenv_undi_get_state PXENV_UNDI_GET_STATE
+ *
+ * UNDI GET STATE
+ *
+ * @{
+ */
+
+/** PXE API function code for pxenv_undi_get_state() */
+#define PXENV_UNDI_GET_STATE 0x0015
+
+/** pxenv_start_undi() has been called */
+#define PXE_UNDI_GET_STATE_STARTED 1
+/** pxenv_undi_initialize() has been called */
+#define PXE_UNDI_GET_STATE_INITIALIZED 2
+/** pxenv_undi_open() has been called */
+#define PXE_UNDI_GET_STATE_OPENED 3
+
+/** Parameter block for pxenv_undi_get_state() */
+struct s_PXENV_UNDI_GET_STATE {
+ PXENV_STATUS_t Status; /**< PXE status code */
+ /** Current state of the UNDI driver
+ *
+ * Valid values are #PXE_UNDI_GET_STATE_STARTED,
+ * #PXE_UNDI_GET_STATE_INITIALIZED or
+ * #PXE_UNDI_GET_STATE_OPENED.
+ */
+ UINT8_t UNDIstate;
+} PACKED;
+
+typedef struct s_PXENV_UNDI_GET_STATE PXENV_UNDI_GET_STATE_t;
+
+extern PXENV_EXIT_t pxenv_undi_get_state ( struct s_PXENV_UNDI_GET_STATE
+ *undi_get_state );
+
+/** @} */ /* pxenv_undi_get_state */
+
+/** @defgroup pxenv_undi_isr PXENV_UNDI_ISR
+ *
+ * UNDI ISR
+ *
+ * @{
+ */
+
+/** PXE API function code for pxenv_undi_isr() */
+#define PXENV_UNDI_ISR 0x0014
+
+/** Determine whether or not this is our interrupt */
+#define PXENV_UNDI_ISR_IN_START 1
+/** Start processing interrupt */
+#define PXENV_UNDI_ISR_IN_PROCESS 2
+/** Continue processing interrupt */
+#define PXENV_UNDI_ISR_IN_GET_NEXT 3
+/** This interrupt was ours */
+#define PXENV_UNDI_ISR_OUT_OURS 0
+/** This interrupt was not ours */
+#define PXENV_UNDI_ISR_OUT_NOT_OURS 1
+/** Finished processing interrupt */
+#define PXENV_UNDI_ISR_OUT_DONE 0
+/** A packet transmission has completed */
+#define PXENV_UNDI_ISR_OUT_TRANSMIT 2
+/** A packet has been received */
+#define PXENV_UNDI_ISR_OUT_RECEIVE 3
+/** We are already in the middle of processing an interrupt */
+#define PXENV_UNDI_ISR_OUT_BUSY 4
+
+/** Unicast packet (or packet captured in promiscuous mode) */
+#define P_DIRECTED 0
+/** Broadcast packet */
+#define P_BROADCAST 1
+/** Multicast packet */
+#define P_MULTICAST 2
+
+/** Parameter block for pxenv_undi_isr() */
+struct s_PXENV_UNDI_ISR {
+ PXENV_STATUS_t Status; /**< PXE status code */
+ /** Function flag
+ *
+ * Valid values are #PXENV_UNDI_ISR_IN_START,
+ * #PXENV_UNDI_ISR_IN_PROCESS, #PXENV_UNDI_ISR_IN_GET_NEXT,
+ * #PXENV_UNDI_ISR_OUT_OURS, #PXENV_UNDI_ISR_OUT_NOT_OURS,
+ * #PXENV_UNDI_ISR_OUT_DONE, #PXENV_UNDI_ISR_OUT_TRANSMIT,
+ * #PXENV_UNDI_ISR_OUT_RECEIVE or #PXENV_UNDI_ISR_OUT_BUSY.
+ */
+ UINT16_t FuncFlag;
+ UINT16_t BufferLength; /**< Data buffer length */
+ UINT16_t FrameLength; /**< Total frame length */
+ UINT16_t FrameHeaderLength; /**< Frame header length */
+ SEGOFF16_t Frame; /**< Data buffer address */
+ /** Protocol type
+ *
+ * Valid values are #P_IP, #P_ARP, #P_RARP or #P_OTHER.
+ */
+ UINT8_t ProtType;
+ /** Packet type
+ *
+ * Valid values are #P_DIRECTED, #P_BROADCAST or #P_MULTICAST.
+ */
+ UINT8_t PktType;
+} PACKED;
+
+typedef struct s_PXENV_UNDI_ISR PXENV_UNDI_ISR_t;
+
+extern PXENV_EXIT_t pxenv_undi_isr ( struct s_PXENV_UNDI_ISR *undi_isr );
+
+/** @} */ /* pxenv_undi_isr */
+
+/** @} */ /* pxe_undi_api */
+
+/** @defgroup pxe_loader_api PXE Loader API
+ *
+ * The UNDI ROM loader API
+ *
+ * @{
+ */
+
+/** The UNDI ROM ID structure */
+struct s_UNDI_ROM_ID {
+ /** Signature
+ *
+ * Contains the bytes 'U', 'N', 'D', 'I'.
+ */
+ UINT32_t Signature;
+ UINT8_t StructLength; /**< Length of this structure */
+ /** Checksum
+ *
+ * The byte checksum of this structure (using the length in
+ * #StructLength) must be zero.
+ */
+ UINT8_t StructCksum;
+ /** Revision of this structure
+ *
+ * For PXE version 2.1, this field must be zero.
+ */
+ UINT8_t StructRev;
+ /** UNDI revision
+ *
+ * UNDI revision, least significant byte first. For UNDI
+ * version 2.1.0, this field will contain { 0x00, 0x01, 0x02 }.
+ */
+ UINT8_t UNDIRev[3];
+ /** UNDI loader routine entry point
+ *
+ * This is the entry point for calling undi_loader().
+ */
+ UINT16_t UNDILoader;
+ /** Minimum required stack segment size */
+ UINT16_t StackSize;
+ /** Minimum required data segment size */
+ UINT16_t DataSize;
+ /** Minimum required code segment size */
+ UINT16_t CodeSize;
+} PACKED;
+
+typedef struct s_UNDI_ROM_ID UNDI_ROM_ID_t;
+
+/** Parameter block for undi_loader() */
+struct s_UNDI_LOADER {
+ /** struct s_UNDI_LOADER starts with a struct s_PXENV_START_UNDI */
+ union undi_loader_start_undi {
+ PXENV_STATUS_t Status; /**< PXE status code */
+ /** Parameters to pass to pxenv_start_undi() */
+ struct s_PXENV_START_UNDI start_undi;
+ } u;
+ /** UNDI data segment
+ *
+ * @note The PXE specification defines the type of this field
+ * as #UINT16_t. For x86, #SEGSEL_t and #UINT16_t are
+ * equivalent anyway; for other architectures #SEGSEL_t makes
+ * more sense.
+ */
+ SEGSEL_t undi_ds;
+ /** UNDI code segment
+ *
+ * @note The PXE specification defines the type of this field
+ * as #UINT16_t. For x86, #SEGSEL_t and #UINT16_t are
+ * equivalent anyway; for other architectures #SEGSEL_t makes
+ * more sense.
+ */
+ SEGSEL_t undi_cs;
+ /** Address of the !PXE structure (a struct s_PXE) */
+ SEGOFF16_t pxe_ptr;
+ /** Address of the PXENV+ structure (a struct s_PXENV) */
+ SEGOFF16_t pxenv_ptr;
+} PACKED;
+
+typedef struct s_UNDI_LOADER UNDI_LOADER_t;
+
+extern PXENV_EXIT_t undi_loader ( struct s_UNDI_LOADER *undi_loader );
+
+/** @} */ /* pxe_loader_api */
+
+/** @} */ /* pxe */
+
+/** @page pxe_notes Etherboot PXE implementation notes
+
+@section pxe_routing IP routing
+
+Several PXE API calls (e.g. pxenv_tftp_open() and pxenv_udp_write())
+allow for the caller to specify a "relay agent IP address", often in a
+field called "gateway" or similar. The PXE specification states that
+"The IP layer should provide space for a minimum of four routing
+entries obtained from the default router and static route DHCP option
+tags in the DHCPACK message, plus any non-zero giaddr field from the
+DHCPOFFER message(s) accepted by the client".
+
+The DHCP static route option ("option static-routes" in dhcpd.conf)
+works only for classed IP routing (i.e. it provides no way to specify
+a subnet mask). Since virtually everything now uses classless IP
+routing, the DHCP static route option is almost totally useless, and
+is (according to the dhcp-options man page) not implemented by any of
+the popular DHCP clients.
+
+This leaves the caller-specified "relay agent IP address", the giaddr
+field from the DHCPOFFER message(s) and the default gateway(s)
+provided via the routers option ("option routers" in dhcpd.conf) in
+the DHCPACK message. Each of these is a default gateway address.
+It's a fair bet that the routers option should take priority over the
+giaddr field, since the routers option has to be explicitly specified
+by the DHCP server operator. Similarly, it's fair to assume that the
+caller-specified "relay agent IP address", if present, should take
+priority over any other routing table entries.
+
+@bug Etherboot currently ignores all potential sources of routing
+information other than the first router provided to it by a DHCP
+routers option.
+
+@section pxe_x86_modes x86 processor mode restrictions
+
+On the x86 platform, different PXE API calls have different
+restrictions on the processor modes (real or protected) that can be
+used. See the individual API call descriptions for the restrictions
+that apply to any particular call.
+
+@subsection pxe_x86_pmode16 Real mode, or protected-mode with 16-bit stack
+
+The PXE specification states that the API function can be called in
+protected mode only if the s_PXE::StatusCallout field is set to a
+non-zero value, and that the API function cannot be called with a
+32-bit stack segment.
+
+Etherboot does not enforce either of these restrictions; they seem (as
+with so much of the PXE specification) to be artifacts of the Intel
+implementation.
+
+*/
+
+#endif /* PXE_API_H */
diff --git a/src/include/pxe_export.h b/src/include/pxe_export.h
deleted file mode 100644
index 3d39e73cf..000000000
--- a/src/include/pxe_export.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/* Header for pxe_export.c
- */
-
-#ifndef PXE_EXPORT_H
-#define PXE_EXPORT_H
-
-#include "pxe.h"
-
-/* Function prototypes */
-extern int ensure_pxe_state ( pxe_stack_state_t wanted );
-
-extern PXENV_EXIT_t pxenv_start_undi ( t_PXENV_START_UNDI * );
-extern PXENV_EXIT_t pxenv_undi_startup ( t_PXENV_UNDI_STARTUP * );
-extern PXENV_EXIT_t pxenv_undi_cleanup ( t_PXENV_UNDI_CLEANUP * );
-extern PXENV_EXIT_t pxenv_undi_initialize ( t_PXENV_UNDI_INITIALIZE * );
-extern PXENV_EXIT_t pxenv_undi_reset_adapter ( t_PXENV_UNDI_RESET_ADAPTER * );
-extern PXENV_EXIT_t pxenv_undi_shutdown ( t_PXENV_UNDI_SHUTDOWN * );
-extern PXENV_EXIT_t pxenv_undi_open ( t_PXENV_UNDI_OPEN * );
-extern PXENV_EXIT_t pxenv_undi_close ( t_PXENV_UNDI_CLOSE * );
-extern PXENV_EXIT_t pxenv_undi_transmit ( t_PXENV_UNDI_TRANSMIT * );
-extern PXENV_EXIT_t pxenv_undi_set_mcast_address (
- t_PXENV_UNDI_SET_MCAST_ADDRESS * );
-extern PXENV_EXIT_t pxenv_undi_set_station_address (
- t_PXENV_UNDI_SET_STATION_ADDRESS * );
-extern PXENV_EXIT_t pxenv_undi_set_packet_filter (
- t_PXENV_UNDI_SET_PACKET_FILTER * );
-extern PXENV_EXIT_t pxenv_undi_get_information (
- t_PXENV_UNDI_GET_INFORMATION * );
-extern PXENV_EXIT_t pxenv_undi_get_statistics ( t_PXENV_UNDI_GET_STATISTICS* );
-extern PXENV_EXIT_t pxenv_undi_clear_statistics (
- t_PXENV_UNDI_CLEAR_STATISTICS * );
-extern PXENV_EXIT_t pxenv_undi_initiate_diags ( t_PXENV_UNDI_INITIATE_DIAGS* );
-extern PXENV_EXIT_t pxenv_undi_force_interrupt (
- t_PXENV_UNDI_FORCE_INTERRUPT * );
-extern PXENV_EXIT_t pxenv_undi_get_mcast_address (
- t_PXENV_UNDI_GET_MCAST_ADDRESS * );
-extern PXENV_EXIT_t pxenv_undi_get_nic_type ( t_PXENV_UNDI_GET_NIC_TYPE * );
-extern PXENV_EXIT_t pxenv_undi_get_iface_info ( t_PXENV_UNDI_GET_IFACE_INFO *);
-extern PXENV_EXIT_t pxenv_undi_isr ( t_PXENV_UNDI_ISR * );
-extern PXENV_EXIT_t pxenv_stop_undi ( t_PXENV_STOP_UNDI * );
-extern PXENV_EXIT_t pxenv_tftp_open ( t_PXENV_TFTP_OPEN * );
-extern PXENV_EXIT_t pxenv_tftp_close ( t_PXENV_TFTP_CLOSE * );
-extern PXENV_EXIT_t pxenv_tftp_read ( t_PXENV_TFTP_READ * );
-extern PXENV_EXIT_t pxenv_tftp_read_file ( t_PXENV_TFTP_READ_FILE * );
-extern PXENV_EXIT_t pxenv_tftp_get_fsize ( t_PXENV_TFTP_GET_FSIZE * );
-extern PXENV_EXIT_t pxenv_udp_open ( t_PXENV_UDP_OPEN * );
-extern PXENV_EXIT_t pxenv_udp_close ( t_PXENV_UDP_CLOSE * );
-extern PXENV_EXIT_t pxenv_udp_read ( t_PXENV_UDP_READ * );
-extern PXENV_EXIT_t pxenv_udp_write ( t_PXENV_UDP_WRITE * );
-extern PXENV_EXIT_t pxenv_unload_stack ( t_PXENV_UNLOAD_STACK * );
-extern PXENV_EXIT_t pxenv_get_cached_info ( t_PXENV_GET_CACHED_INFO * );
-extern PXENV_EXIT_t pxenv_restart_tftp ( t_PXENV_RESTART_TFTP * );
-extern PXENV_EXIT_t pxenv_start_base ( t_PXENV_START_BASE * );
-extern PXENV_EXIT_t pxenv_stop_base ( t_PXENV_STOP_BASE * );
-
-extern PXENV_EXIT_t pxe_api_call ( int opcode, t_PXENV_ANY *params );
-
-/* Static variables */
-extern pxe_stack_t *pxe_stack;
-
-#endif /* PXE_EXPORT_H */
diff --git a/src/include/pxe_types.h b/src/include/pxe_types.h
new file mode 100644
index 000000000..80e6aa17c
--- /dev/null
+++ b/src/include/pxe_types.h
@@ -0,0 +1,126 @@
+#ifndef PXE_TYPES_H
+#define PXE_TYPES_H
+
+/** @file
+ *
+ * PXE data types
+ *
+ */
+
+#include "stdint.h"
+#include "pxe_addr.h" /* Architecture-specific PXE definitions */
+#include "errno.h" /* PXE status codes */
+
+/** @addtogroup pxe Preboot eXecution Environment (PXE) API
+ * @{
+ */
+
+/** @defgroup pxe_types PXE data types
+ *
+ * Basic PXE data types such as #UINT16_t, #ADDR32_t, #SEGSEL_t etc.
+ *
+ * These definitions are based on Table 1-1 ("Data Type Definitions")
+ * in the Intel PXE specification version 2.1. They have been
+ * generalised to non-x86 architectures where possible.
+ *
+ * @{
+ */
+
+/** An 8-bit unsigned integer */
+typedef uint8_t UINT8_t;
+
+/** A 16-bit unsigned integer */
+typedef uint16_t UINT16_t;
+
+/** A 32-bit unsigned integer */
+typedef uint32_t UINT32_t;
+
+/** A PXE exit code.
+ *
+ * Permitted values are #PXENV_EXIT_SUCCESS and #PXENV_EXIT_FAILURE.
+ *
+ */
+typedef UINT16_t PXENV_EXIT_t;
+#define PXENV_EXIT_SUCCESS 0x0000 /**< No error occurred */
+#define PXENV_EXIT_FAILURE 0x0001 /**< An error occurred */
+
+/** A PXE status code.
+ *
+ * Status codes are defined in errno.h.
+ *
+ */
+typedef UINT16_t PXENV_STATUS_t;
+
+/** An IPv4 address.
+ *
+ * @note This data type is in network (big-endian) byte order.
+ *
+ */
+typedef UINT32_t IP4_t;
+
+/** A UDP port.
+ *
+ * @note This data type is in network (big-endian) byte order.
+ *
+ */
+typedef UINT16_t UDP_PORT_t;
+
+/** Maximum length of a MAC address */
+#define MAC_ADDR_LEN 16
+
+/** A MAC address */
+typedef UINT8_t MAC_ADDR_t[MAC_ADDR_LEN];
+
+#ifndef HAVE_ARCH_ADDR32
+/** A physical address.
+ *
+ * For x86, this is a 32-bit physical address, and is therefore
+ * limited to the low 4GB.
+ *
+ */
+typedef UINT32_t ADDR32_t;
+#endif
+
+#ifndef HAVE_ARCH_SEGSEL
+/** A segment selector.
+ *
+ * For x86, this is a real mode segment (0x0000-0xffff), or a
+ * protected-mode segment selector, such as could be loaded into a
+ * segment register.
+ *
+ */
+typedef UINT16_t SEGSEL_t;
+#endif
+
+#ifndef HAVE_ARCH_OFF16
+/** An offset within a segment identified by #SEGSEL
+ *
+ * For x86, this is a 16-bit offset.
+ *
+ */
+typedef UINT16_t OFF16_t;
+#endif
+
+/** A segment:offset address
+ *
+ * For x86, this is a 16-bit real-mode or protected-mode
+ * segment:offset address.
+ *
+ */
+typedef struct s_SEGOFF16 {
+ OFF16_t offset; /**< Offset within the segment */
+ SEGSEL_t segment; /**< Segment selector */
+} PACKED SEGOFF16_t;
+
+/** A segment descriptor */
+typedef struct s_SEGDESC {
+ SEGSEL_t segment_address; /**< Segment selector */
+ ADDR32_t physical_address; /**< Segment base address */
+ OFF16_t seg_size; /**< Size of the segment */
+} PACKED SEGDESC_t;
+
+/** @} */ /* pxe_types */
+
+/** @} */ /* pxe */
+
+#endif /* PXE_TYPES_H */
diff --git a/src/include/tables.h b/src/include/tables.h
index 26ad61db7..c3e05e55e 100644
--- a/src/include/tables.h
+++ b/src/include/tables.h
@@ -1,47 +1,171 @@
#ifndef TABLES_H
#define TABLES_H
-/*
- * Macros for dealing with linker-generated tables of fixed-size
- * symbols. We make fairly extensive use of these in order to avoid
- * ifdef spaghetti and/or linker symbol pollution. For example,
- * instead of having code such as
+/** @page ifdef_harmful #ifdef considered harmful
+ *
+ * Overuse of @c #ifdef has long been a problem in Etherboot.
+ * Etherboot provides a rich array of features, but all these features
+ * take up valuable space in a ROM image. The traditional solution to
+ * this problem has been for each feature to have its own @c #ifdef
+ * option, allowing the feature to be compiled in only if desired.
+ *
+ * The problem with this is that it becomes impossible to compile, let
+ * alone test, all possible versions of Etherboot. Code that is not
+ * typically used tends to suffer from bit-rot over time. It becomes
+ * extremely difficult to predict which combinations of compile-time
+ * options will result in code that can even compile and link
+ * correctly.
+ *
+ * To solve this problem, we have adopted a new approach from
+ * Etherboot 5.5 onwards. @c #ifdef is now "considered harmful", and
+ * its use should be minimised. Separate features should be
+ * implemented in separate @c .c files, and should \b always be
+ * compiled (i.e. they should \b not be guarded with a @c #ifdef @c
+ * MY_PET_FEATURE statement). By making (almost) all code always
+ * compile, we avoid the problem of bit-rot in rarely-used code.
+ *
+ * The file config.h, in combination with the @c make command line,
+ * specifies the objects that will be included in any particular build
+ * of Etherboot. For example, suppose that config.h includes the line
+ *
+ * @code
+ *
+ * #define CONSOLE_SERIAL
+ * #define DOWNLOAD_PROTO_TFTP
+ *
+ * @endcode
+ *
+ * When a particular Etherboot image (e.g. @c bin/rtl8139.zdsk) is
+ * built, the options specified in config.h are used to drag in the
+ * relevant objects at link-time. For the above example, serial.o and
+ * tftp.o would be linked in.
+ *
+ * There remains one problem to solve: how do these objects get used?
+ * Traditionally, we had code such as
+ *
+ * @code
+ *
+ * #ifdef CONSOLE_SERIAL
+ * serial_init();
+ * #endif
+ *
+ * @endcode
+ *
+ * in main.c, but this reintroduces @c #ifdef and so is a Bad Idea.
+ * We cannot simply remove the @c #ifdef and make it
+ *
+ * @code
*
- * #ifdef CONSOLE_SERIAL
* serial_init();
- * #endif
+ *
+ * @endcode
+ *
+ * because then serial.o would end up always being linked in.
+ *
+ * The solution is to use @link tables.h linker tables @endlink.
+ *
+ */
+
+/** @file
+ *
+ * Linker tables
+ *
+ * Read @ref ifdef_harmful first for some background on the motivation
+ * for using linker tables.
+ *
+ * This file provides macros for dealing with linker-generated tables
+ * of fixed-size symbols. We make fairly extensive use of these in
+ * order to avoid @c #ifdef spaghetti and/or linker symbol pollution.
+ * For example, instead of having code such as
+ *
+ * @code
+ *
+ * #ifdef CONSOLE_SERIAL
+ * serial_init();
+ * #endif
+ *
+ * @endcode
*
* we make serial.c generate an entry in the initialisation function
* table, and then have a function call_init_fns() that simply calls
* all functions present in this table. If and only if serial.o gets
* linked in, then its initialisation function will be called. We
* avoid linker symbol pollution (i.e. always dragging in serial.o
- * just because of a call to serial_init()) and we also avoid ifdef
- * spaghetti (having to conditionalise every reference to functions in
- * serial.c).
+ * just because of a call to serial_init()) and we also avoid @c
+ * #ifdef spaghetti (having to conditionalise every reference to
+ * functions in serial.c).
*
* The linker script takes care of assembling the tables for us. All
- * our table sections have names of the format ".tbl.NAME.NN" where
- * NAME designates the data structure stored in the table
- * (e.g. "init_fn") and NN is a two-digit decimal number used to
- * impose an ordering upon the tables if required. NN=00 is reserved
- * for the symbol indicating "table start", and NN=99 is reserved for
- * the symbol indicating "table end".
+ * our table sections have names of the format @c .tbl.NAME.NN where
+ * @c NAME designates the data structure stored in the table (e.g. @c
+ * init_fn) and @c NN is a two-digit decimal number used to impose an
+ * ordering upon the tables if required. @c NN=00 is reserved for the
+ * symbol indicating "table start", and @c NN=99 is reserved for the
+ * symbol indicating "table end".
+ *
+ * As an example, suppose that we want to create a "frobnicator"
+ * feature framework, and allow for several independent modules to
+ * provide frobnicating services. Then we would create a frob.h
+ * header file containing e.g.
+ *
+ * @code
+ *
+ * struct frobnicator {
+ * const char *name; // Name of the frobnicator
+ * void ( *frob ) ( void ); // The frobnicating function itself
+ * };
+ *
+ * #define __frobnicator __table ( frobnicators, 01 )
+ *
+ * @endcode
*
- * To define an entry in the "xxx" table:
+ * Any module providing frobnicating services would look something
+ * like
*
- * static struct xxx my_xxx __table(xxx,01) = { ... };
+ * @code
*
- * To access start and end markers for the "xxx" table:
+ * #include "frob.h"
*
- * static struct xxx xxx_start[0] __table_start(xxx);
- * static struct xxx xxx_end[0] __table_end(xxx);
+ * static void my_frob ( void ) {
+ * // Do my frobnicating
+ * ...
+ * }
*
- * See init.h and init.c for an example of how these macros are used
- * in practice.
+ * static struct frob my_frobnicator __frobnicator = {
+ * .name = "my_frob",
+ * .frob = my_frob,
+ * };
+ *
+ * @endcode
+ *
+ * The central frobnicator code (frob.c) would use the frobnicating
+ * modules as follows
+ *
+ * @code
+ *
+ * #include "frob.h"
+ *
+ * static struct frob frob_start[0] __table_start ( frobnicators );
+ * static struct frob frob_end[0] __table_end ( frobnicators );
+ *
+ * // Call all linked-in frobnicators
+ * void frob_all ( void ) {
+ * struct frob *frob;
+ *
+ * for ( frob = frob_start ; frob < frob_end ; frob++ ) {
+ * printf ( "Calling frobnicator \"%s\"\n", frob->name );
+ * frob->frob ();
+ * }
+ * }
+ *
+ * @endcode
+ *
+ * See init.h and init.c for a real-life example.
*
*/
+#include "compiler.h" /* for doxygen */
+
#define __table_str(x) #x
#define __table_section(table,idx) \
__section__ ( ".tbl." __table_str(table) "." __table_str(idx) )
@@ -49,10 +173,54 @@
#define __table_section_start(table) __table_section(table,00)
#define __table_section_end(table) __table_section(table,99)
+
+/**
+ * Linker table entry.
+ *
+ * Declares a data structure to be part of a linker table. Use as
+ * e.g.
+ *
+ * @code
+ *
+ * static struct my_foo __table ( foo, 01 ) = {
+ * ...
+ * };
+ *
+ * @endcode
+ *
+ */
#define __table(table,idx) \
__attribute__ (( unused, __table_section(table,idx) ))
+
+/**
+ * Linker table start marker.
+ *
+ * Declares a data structure (usually an empty data structure) to be
+ * the start of a linker table. Use as e.g.
+ *
+ * @code
+ *
+ * static struct foo_start[0] __table_start ( foo );
+ *
+ * @endcode
+ *
+ */
#define __table_start(table) \
__attribute__ (( unused, __table_section_start(table) ))
+
+/**
+ * Linker table end marker.
+ *
+ * Declares a data structure (usually an empty data structure) to be
+ * the end of a linker table. Use as e.g.
+ *
+ * @code
+ *
+ * static struct foo_end[0] __table_end ( foo );
+ *
+ * @endcode
+ *
+ */
#define __table_end(table) \
__attribute__ (( unused, __table_section_end(table) ))
diff --git a/src/include/tftp.h b/src/include/tftp.h
index 70192067c..2a086eb2b 100644
--- a/src/include/tftp.h
+++ b/src/include/tftp.h
@@ -1,13 +1,17 @@
#ifndef TFTP_H
#define TFTP_H
+/** @file */
+
#include "in.h"
#include "buffer.h"
#include "nic.h"
+#include "ip.h"
+#include "udp.h"
-#define TFTP_PORT 69
-#define TFTP_DEFAULTSIZE_PACKET 512
-#define TFTP_MAX_PACKET 1432 /* 512 */
+#define TFTP_PORT 69 /**< Default TFTP server port */
+#define TFTP_DEFAULT_BLKSIZE 512
+#define TFTP_MAX_BLKSIZE 1432 /* 512 */
#define TFTP_RRQ 1
#define TFTP_WRQ 2
@@ -16,53 +20,131 @@
#define TFTP_ERROR 5
#define TFTP_OACK 6
-#define TFTP_CODE_EOF 1
-#define TFTP_CODE_MORE 2
-#define TFTP_CODE_ERROR 3
-#define TFTP_CODE_BOOT 4
-#define TFTP_CODE_CFG 5
+#define TFTP_ERR_FILE_NOT_FOUND 1 /**< File not found */
+#define TFTP_ERR_ACCESS_DENIED 2 /**< Access violation */
+#define TFTP_ERR_DISK_FULL 3 /**< Disk full or allocation exceeded */
+#define TFTP_ERR_ILLEGAL_OP 4 /**< Illegal TFTP operation */
+#define TFTP_ERR_UNKNOWN_TID 5 /**< Unknown transfer ID */
+#define TFTP_ERR_FILE_EXISTS 6 /**< File already exists */
+#define TFTP_ERR_UNKNOWN_USER 7 /**< No such user */
+#define TFTP_ERR_BAD_OPTS 8 /**< Option negotiation failed */
+
+/** A TFTP request (RRQ) packet */
+struct tftp_rrq {
+ struct iphdr ip;
+ struct udphdr udp;
+ uint16_t opcode;
+ char data[TFTP_DEFAULT_BLKSIZE];
+} PACKED;
+
+/** A TFTP data (DATA) packet */
+struct tftp_data {
+ struct iphdr ip;
+ struct udphdr udp;
+ uint16_t opcode;
+ uint16_t block;
+ uint8_t data[TFTP_MAX_BLKSIZE];
+} PACKED;
+
+/** A TFTP acknowledgement (ACK) packet */
+struct tftp_ack {
+ struct iphdr ip;
+ struct udphdr udp;
+ uint16_t opcode;
+ uint16_t block;
+} PACKED;
+
+/** A TFTP error (ERROR) packet */
+struct tftp_error {
+ struct iphdr ip;
+ struct udphdr udp;
+ uint16_t opcode;
+ uint16_t errcode;
+ char errmsg[TFTP_DEFAULT_BLKSIZE];
+} PACKED;
-struct tftp_t {
+/** A TFTP options acknowledgement (OACK) packet */
+struct tftp_oack {
struct iphdr ip;
struct udphdr udp;
uint16_t opcode;
- union {
- uint8_t rrq[TFTP_DEFAULTSIZE_PACKET];
- struct {
- uint16_t block;
- uint8_t download[TFTP_MAX_PACKET];
- } data;
- struct {
- uint16_t block;
- } ack;
- struct {
- uint16_t errcode;
- uint8_t errmsg[TFTP_DEFAULTSIZE_PACKET];
- } err;
- struct {
- uint8_t data[TFTP_DEFAULTSIZE_PACKET+2];
- } oack;
- } u;
+ uint8_t data[TFTP_DEFAULT_BLKSIZE];
} PACKED;
-/* define a smaller tftp packet solely for making requests to conserve stack
- 512 bytes should be enough */
-struct tftpreq_t {
+/** The common header of all TFTP packets */
+struct tftp_common {
struct iphdr ip;
struct udphdr udp;
uint16_t opcode;
- union {
- uint8_t rrq[512];
- struct {
- uint16_t block;
- } ack;
- struct {
- uint16_t errcode;
- uint8_t errmsg[512-2];
- } err;
- } u;
} PACKED;
+/** A union encapsulating all TFTP packet types */
+union tftp_any {
+ struct tftp_common common;
+ struct tftp_rrq rrq;
+ struct tftp_data data;
+ struct tftp_ack ack;
+ struct tftp_error error;
+ struct tftp_oack oack;
+};
+
+/**
+ * TFTP state
+ *
+ * This data structure holds the state for an ongoing TFTP transfer.
+ */
+struct tftp_state {
+ /** TFTP server address
+ *
+ * This is the IP address and UDP port from which data packets
+ * will be sent, and to which ACK packets should be sent.
+ */
+ struct sockaddr_in server;
+ /** TFTP client port
+ *
+ * This is the UDP port from which the open request will be
+ * sent, and to which any unicast data packets will be sent.
+ */
+ in_port_t lport;
+ /** TFTP multicast address
+ *
+ * This is the IP address and UDP port to which multicast data
+ * packets, if any, will be sent.
+ */
+ struct sockaddr_in multicast;
+ /** Master client
+ *
+ * This will be true if the client is the master client for a
+ * multicast protocol (i.e. MTFTP or TFTM). (It will always
+ * be true for a non-multicast protocol, i.e. plain old TFTP).
+ */
+ int master;
+ /** Data block size
+ *
+ * This is the "blksize" option negotiated with the TFTP
+ * server. (If the TFTP server does not support TFTP options,
+ * this will default to 512).
+ */
+ unsigned int blksize;
+ /** File size
+ *
+ * This is the value returned in the "tsize" option from the
+ * TFTP server. If the TFTP server does not support the
+ * "tsize" option, this value will be zero.
+ */
+ off_t tsize;
+ /** Last received block
+ *
+ * The block number of the most recent block received from the
+ * TFTP server. Note that the first data block is block 1; a
+ * value of 0 indicates that no data blocks have yet been
+ * received.
+ */
+ unsigned int block;
+};
+
+
+
struct tftpreq_info_t {
struct sockaddr_in *server;
const char *name;
@@ -78,13 +160,4 @@ struct tftpblk_info_t {
#define TFTP_MIN_PACKET (sizeof(struct iphdr) + sizeof(struct udphdr) + 4)
-/*
- * Functions in tftp.c. Needed for pxe_export.c
- *
- */
-extern int tftp_block ( struct tftpreq_info_t *request,
- struct tftpblk_info_t *block );
-extern int tftp ( char *url, struct sockaddr_in *server, char *file,
- struct buffer *buffer );
-
#endif /* TFTP_H */
diff --git a/src/include/tftpcore.h b/src/include/tftpcore.h
new file mode 100644
index 000000000..52f63bd9c
--- /dev/null
+++ b/src/include/tftpcore.h
@@ -0,0 +1,33 @@
+#ifndef TFTPCORE_H
+#define TFTPCORE_H
+
+/** @file
+ *
+ * TFTP core functions
+ *
+ * This file provides functions that are common to the TFTP (rfc1350),
+ * TFTM (rfc2090) and MTFTP (PXE) protocols.
+ *
+ */
+
+#include "tftp.h"
+
+extern int tftp_open ( struct tftp_state *state, const char *filename,
+ union tftp_any **reply, int multicast );
+
+extern int tftp_process_opts ( struct tftp_state *state,
+ struct tftp_oack *oack );
+
+extern int tftp_ack_nowait ( struct tftp_state *state );
+
+extern int tftp_get ( struct tftp_state *state, long timeout,
+ union tftp_any **reply );
+
+extern int tftp_ack ( struct tftp_state *state, union tftp_any **reply );
+
+extern int tftp_error ( struct tftp_state *state, int errcode,
+ const char *errmsg );
+
+extern void tftp_set_errno ( struct tftp_error *error );
+
+#endif /* TFTPCORE_H */
diff --git a/src/include/vsprintf.h b/src/include/vsprintf.h
index 2bf200852..122fcc66e 100644
--- a/src/include/vsprintf.h
+++ b/src/include/vsprintf.h
@@ -1,14 +1,50 @@
#ifndef VSPRINTF_H
#define VSPRINTF_H
-/*
- * Note that we cannot use __attribute__ (( format ( printf, ... ) ))
- * to get automatic type checking on arguments, because we use
- * non-standard format characters such as "%!" and "%@".
+/** @file
+ *
+ * printf and friends.
+ *
+ * Etherboot's printf() functions understand the following format
+ * specifiers:
+ *
+ * - Hexadecimal integers
+ * - @c %[#]x - 4 bytes int (8 hex digits, lower case)
+ * - @c %[#]X - 4 bytes int (8 hex digits, upper case)
+ * - @c %[#]lx - 8 bytes long (16 hex digits, lower case)
+ * - @c %[#]lX - 8 bytes long (16 hex digits, upper case)
+ * - @c %[#]hx - 2 bytes int (4 hex digits, lower case)
+ * - @c %[#]hX - 2 bytes int (4 hex digits, upper case)
+ * - @c %[#]hhx - 1 byte int (2 hex digits, lower case)
+ * - @c %[#]hhX - 1 byte int (2 hex digits, upper case)
+ * .
+ * If the optional # prefix is specified, the output will
+ * be prefixed with 0x (or 0X).
+ *
+ * - Other integers
+ * - @c %d - decimal int
+ * .
+ * Note that any width specification (e.g. the @c 02 in @c %02x)
+ * will be accepted but ignored.
+ *
+ * - Strings and characters
+ * - @c %c - char
+ * - @c %s - string
+ * - @c %m - error message text (i.e. strerror(errno))
+ *
+ * - Etherboot-specific specifiers
+ * - @c %@ - IP address in ddd.ddd.ddd.ddd notation
+ * - @c %! - MAC address in xx:xx:xx:xx:xx:xx notation
+ *
+ *
+ * @note Unfortunately, we cannot use <tt> __attribute__ (( format (
+ * printf, ... ) )) </tt> to get automatic type checking on arguments,
+ * because we use non-standard format characters such as @c %! and
+ * @c %@.
*
*/
extern int sprintf ( char *buf, const char *fmt, ... );
-extern void printf ( const char *fmt, ... );
+extern int printf ( const char *fmt, ... );
#endif /* VSPRINTF_H */
diff --git a/src/interface/pxe/pxe.c b/src/interface/pxe/pxe.c
new file mode 100644
index 000000000..06e6121f7
--- /dev/null
+++ b/src/interface/pxe/pxe.c
@@ -0,0 +1,311 @@
+/** @file
+ *
+ *
+ *
+ */
+
+/*
+ * Copyright (C) 2004 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * 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.
+ */
+
+#include "pxe.h"
+
+/* Global pointer to currently installed PXE stack */
+pxe_stack_t *pxe_stack = NULL;
+
+/* Various startup/shutdown routines. The startup/shutdown call
+ * sequence is incredibly badly defined in the Intel PXE spec, for
+ * example:
+ *
+ * PXENV_UNDI_INITIALIZE says that the parameters used to initialize
+ * the adaptor should be those supplied to the most recent
+ * PXENV_UNDI_STARTUP call. PXENV_UNDI_STARTUP takes no parameters.
+ *
+ * PXENV_UNDI_CLEANUP says that the rest of the API will not be
+ * available after making this call. Figure 3-3 ("Early UNDI API
+ * usage") shows a call to PXENV_UNDI_CLEANUP being followed by a
+ * call to the supposedly now unavailable PXENV_STOP_UNDI.
+ *
+ * PXENV_UNLOAD_BASE_STACK talks about freeing up the memory
+ * occupied by the PXE stack. Figure 4-3 ("PXE IPL") shows a call
+ * to PXENV_STOP_UNDI being made after the call to
+ * PXENV_UNLOAD_BASE_STACK, by which time the entire PXE stack
+ * should have been freed (and, potentially, zeroed).
+ *
+ * Nothing, anywhere, seems to mention who's responsible for freeing
+ * up the base memory allocated for the stack segment. It's not
+ * even clear whether or not this is expected to be in free base
+ * memory rather than claimed base memory.
+ *
+ * Consequently, we adopt a rather defensive strategy, designed to
+ * work with any conceivable sequence of initialisation or shutdown
+ * calls. We have only two things that we care about:
+ *
+ * 1. Have we hooked INT 1A and INT 15,E820(etc.)?
+ * 2. Is the NIC initialised?
+ *
+ * The NIC should never be initialised without the vectors being
+ * hooked, similarly the vectors should never be unhooked with the NIC
+ * still initialised. We do, however, want to be able to have the
+ * vectors hooked with the NIC shutdown. We therefore have three
+ * possible states:
+ *
+ * 1. Ready to unload: interrupts unhooked, NIC shutdown.
+ * 2. Midway: interrupts hooked, NIC shutdown.
+ * 3. Fully ready: interrupts hooked, NIC initialised.
+ *
+ * We provide the three states CAN_UNLOAD, MIDWAY and READY to define
+ * these, and the call pxe_ensure_state() to ensure that the stack is
+ * in the specified state. All our PXE API call implementations
+ * should use this call to ensure that the state is as required for
+ * that PXE API call. This enables us to cope with whatever the
+ * end-user's interpretation of the PXE spec may be. It even allows
+ * for someone calling e.g. PXENV_START_UNDI followed by
+ * PXENV_UDP_WRITE, without bothering with any of the intervening
+ * calls.
+ *
+ * pxe_ensure_state() returns 1 for success, 0 for failure. In the
+ * event of failure (which can arise from e.g. asking for state READY
+ * when we don't know where our NIC is), the error code
+ * PXENV_STATUS_UNDI_INVALID_STATE should be returned to the user.
+ * The macros ENSURE_XXX() can be used to achieve this without lots of
+ * duplicated code.
+ */
+
+/* pxe_[un]hook_stack are architecture-specific and provided in
+ * pxe_callbacks.c
+ */
+
+int pxe_initialise_nic ( void ) {
+ if ( pxe_stack->state >= READY ) return 1;
+
+#warning "device probing mechanism has completely changed"
+#if 0
+
+ /* Check if NIC is initialised. dev.disable is set to 0
+ * when disable() is called, so we use this.
+ */
+ if ( dev.disable ) {
+ /* NIC may have been initialised independently
+ * (e.g. when we set up the stack prior to calling the
+ * NBP).
+ */
+ pxe_stack->state = READY;
+ return 1;
+ }
+
+ /* If we already have a NIC defined, reuse that one with
+ * PROBE_AWAKE. If one was specifed via PXENV_START_UNDI, try
+ * that one first. Otherwise, set PROBE_FIRST.
+ */
+
+ if ( dev.state.pci.dev.use_specified == 1 ) {
+ dev.how_probe = PROBE_NEXT;
+ DBG ( " initialising NIC specified via START_UNDI" );
+ } else if ( dev.state.pci.dev.driver ) {
+ DBG ( " reinitialising NIC" );
+ dev.how_probe = PROBE_AWAKE;
+ } else {
+ DBG ( " probing for any NIC" );
+ dev.how_probe = PROBE_FIRST;
+ }
+
+ /* Call probe routine to bring up the NIC */
+ if ( eth_probe ( &dev ) != PROBE_WORKED ) {
+ DBG ( " failed" );
+ return 0;
+ }
+#endif
+
+
+ pxe_stack->state = READY;
+ return 1;
+}
+
+int pxe_shutdown_nic ( void ) {
+ if ( pxe_stack->state <= MIDWAY ) return 1;
+
+ eth_irq ( DISABLE );
+ disable ( &dev );
+ pxe_stack->state = MIDWAY;
+ return 1;
+}
+
+int ensure_pxe_state ( pxe_stack_state_t wanted ) {
+ int success = 1;
+
+ if ( ! pxe_stack ) return 0;
+ if ( wanted >= MIDWAY )
+ success = success & hook_pxe_stack();
+ if ( wanted > MIDWAY ) {
+ success = success & pxe_initialise_nic();
+ } else {
+ success = success & pxe_shutdown_nic();
+ }
+ if ( wanted < MIDWAY )
+ success = success & unhook_pxe_stack();
+ return success;
+}
+
+/* API call dispatcher
+ *
+ * Status: complete
+ */
+PXENV_EXIT_t pxe_api_call ( int opcode, union u_PXENV_ANY *any ) {
+ PXENV_EXIT_t ret = PXENV_EXIT_FAILURE;
+
+ /* Set default status in case child routine fails to do so */
+ any->Status = PXENV_STATUS_FAILURE;
+
+ DBG ( "[" );
+
+ /* Hand off to relevant API routine */
+ switch ( opcode ) {
+ case PXENV_START_UNDI:
+ ret = pxenv_start_undi ( &any->start_undi );
+ break;
+ case PXENV_UNDI_STARTUP:
+ ret = pxenv_undi_startup ( &any->undi_startup );
+ break;
+ case PXENV_UNDI_CLEANUP:
+ ret = pxenv_undi_cleanup ( &any->undi_cleanup );
+ break;
+ case PXENV_UNDI_INITIALIZE:
+ ret = pxenv_undi_initialize ( &any->undi_initialize );
+ break;
+ case PXENV_UNDI_RESET_ADAPTER:
+ ret = pxenv_undi_reset_adapter ( &any->undi_reset_adapter );
+ break;
+ case PXENV_UNDI_SHUTDOWN:
+ ret = pxenv_undi_shutdown ( &any->undi_shutdown );
+ break;
+ case PXENV_UNDI_OPEN:
+ ret = pxenv_undi_open ( &any->undi_open );
+ break;
+ case PXENV_UNDI_CLOSE:
+ ret = pxenv_undi_close ( &any->undi_close );
+ break;
+ case PXENV_UNDI_TRANSMIT:
+ ret = pxenv_undi_transmit ( &any->undi_transmit );
+ break;
+ case PXENV_UNDI_SET_MCAST_ADDRESS:
+ ret = pxenv_undi_set_mcast_address (
+ &any->undi_set_mcast_address );
+ break;
+ case PXENV_UNDI_SET_STATION_ADDRESS:
+ ret = pxenv_undi_set_station_address (
+ &any->undi_set_station_address );
+ break;
+ case PXENV_UNDI_SET_PACKET_FILTER:
+ ret = pxenv_undi_set_packet_filter (
+ &any->undi_set_packet_filter );
+ break;
+ case PXENV_UNDI_GET_INFORMATION:
+ ret = pxenv_undi_get_information (
+ &any->undi_get_information );
+ break;
+ case PXENV_UNDI_GET_STATISTICS:
+ ret = pxenv_undi_get_statistics ( &any->undi_get_statistics );
+ break;
+ case PXENV_UNDI_CLEAR_STATISTICS:
+ ret = pxenv_undi_clear_statistics (
+ &any->undi_clear_statistics );
+ break;
+ case PXENV_UNDI_INITIATE_DIAGS:
+ ret = pxenv_undi_initiate_diags ( &any->undi_initiate_diags );
+
+ break;
+ case PXENV_UNDI_FORCE_INTERRUPT:
+ ret = pxenv_undi_force_interrupt (
+ &any->undi_force_interrupt );
+ break;
+ case PXENV_UNDI_GET_MCAST_ADDRESS:
+ ret = pxenv_undi_get_mcast_address (
+ &any->undi_get_mcast_address );
+ break;
+ case PXENV_UNDI_GET_NIC_TYPE:
+ ret = pxenv_undi_get_nic_type ( &any->undi_get_nic_type );
+ break;
+ case PXENV_UNDI_GET_IFACE_INFO:
+ ret = pxenv_undi_get_iface_info ( &any->undi_get_iface_info );
+ break;
+ case PXENV_UNDI_ISR:
+ ret = pxenv_undi_isr ( &any->undi_isr );
+ break;
+ case PXENV_STOP_UNDI:
+ ret = pxenv_stop_undi ( &any->stop_undi );
+ break;
+ case PXENV_TFTP_OPEN:
+ ret = pxenv_tftp_open ( &any->tftp_open );
+ break;
+ case PXENV_TFTP_CLOSE:
+ ret = pxenv_tftp_close ( &any->tftp_close );
+ break;
+ case PXENV_TFTP_READ:
+ ret = pxenv_tftp_read ( &any->tftp_read );
+ break;
+ case PXENV_TFTP_READ_FILE:
+ ret = pxenv_tftp_read_file ( &any->tftp_read_file );
+ break;
+ case PXENV_TFTP_GET_FSIZE:
+ ret = pxenv_tftp_get_fsize ( &any->tftp_get_fsize );
+ break;
+ case PXENV_UDP_OPEN:
+ ret = pxenv_udp_open ( &any->udp_open );
+ break;
+ case PXENV_UDP_CLOSE:
+ ret = pxenv_udp_close ( &any->udp_close );
+ break;
+ case PXENV_UDP_READ:
+ ret = pxenv_udp_read ( &any->udp_read );
+ break;
+ case PXENV_UDP_WRITE:
+ ret = pxenv_udp_write ( &any->udp_write );
+ break;
+ case PXENV_UNLOAD_STACK:
+ ret = pxenv_unload_stack ( &any->unload_stack );
+ break;
+ case PXENV_GET_CACHED_INFO:
+ ret = pxenv_get_cached_info ( &any->get_cached_info );
+ break;
+ case PXENV_RESTART_TFTP:
+ ret = pxenv_restart_tftp ( &any->restart_tftp );
+ break;
+ case PXENV_START_BASE:
+ ret = pxenv_start_base ( &any->start_base );
+ break;
+ case PXENV_STOP_BASE:
+ ret = pxenv_stop_base ( &any->stop_base );
+ break;
+
+ default:
+ DBG ( "PXENV_UNKNOWN_%hx", opcode );
+ any->Status = PXENV_STATUS_UNSUPPORTED;
+ ret = PXENV_EXIT_FAILURE;
+ break;
+ }
+
+ if ( any->Status != PXENV_STATUS_SUCCESS ) {
+ DBG ( " %hx", any->Status );
+ }
+ if ( ret != PXENV_EXIT_SUCCESS ) {
+ DBG ( ret == PXENV_EXIT_FAILURE ? " err" : " ??" );
+ }
+ DBG ( "]" );
+
+ return ret;
+}
diff --git a/src/interface/pxe/pxe_errors.c b/src/interface/pxe/pxe_errors.c
new file mode 100644
index 000000000..581393e81
--- /dev/null
+++ b/src/interface/pxe/pxe_errors.c
@@ -0,0 +1,102 @@
+#include "errno.h"
+
+/*
+ * This table was generated from the relevant section of errno.h using
+ *
+ * perl -ne 'if ( /(PXENV_STATUS_(\S+))/ ) {
+ * $code = $1; $msg = $2;
+ * $msg =~ s/_/ /g; $msg = ucfirst lc $msg;
+ * $msg =~ s/(tftp|udp|arp|undi|bis|binl|pxenv|pxe|dhcp)/uc $1/ieg;
+ * print "\t{ $code, \"$msg\" },\n";
+ * }'
+ *
+ * followed by a little manual tweaking.
+ *
+ */
+static struct errortab pxe_errortab[] __errortab = {
+ { PXENV_STATUS_SUCCESS, "Success" },
+ { PXENV_STATUS_FAILURE, "Failure" },
+ { PXENV_STATUS_BAD_FUNC, "Bad function" },
+ { PXENV_STATUS_UNSUPPORTED, "Unsupported function" },
+ { PXENV_STATUS_KEEP_UNDI, "Keep UNDI" },
+ { PXENV_STATUS_KEEP_ALL, "Keep all" },
+ { PXENV_STATUS_OUT_OF_RESOURCES, "Out of resources" },
+ { PXENV_STATUS_ARP_TIMEOUT, "ARP timeout" },
+ { PXENV_STATUS_UDP_CLOSED, "UDP closed" },
+ { PXENV_STATUS_UDP_OPEN, "UDP open" },
+ { PXENV_STATUS_TFTP_CLOSED, "TFTP closed" },
+ { PXENV_STATUS_TFTP_OPEN, "TFTP open" },
+ { PXENV_STATUS_MCOPY_PROBLEM, "Memory copy problem" },
+ { PXENV_STATUS_BIS_INTEGRITY_FAILURE, "BIS integrity failure" },
+ { PXENV_STATUS_BIS_VALIDATE_FAILURE, "BIS validation failure" },
+ { PXENV_STATUS_BIS_INIT_FAILURE, "BIS init failure" },
+ { PXENV_STATUS_BIS_SHUTDOWN_FAILURE, "BIS shutdown failure" },
+ { PXENV_STATUS_BIS_GBOA_FAILURE, "BIS GBOA failure" },
+ { PXENV_STATUS_BIS_FREE_FAILURE, "BIS free failure" },
+ { PXENV_STATUS_BIS_GSI_FAILURE, "BIS GSI failure" },
+ { PXENV_STATUS_BIS_BAD_CKSUM, "BIS bad checksum" },
+ { PXENV_STATUS_TFTP_CANNOT_ARP_ADDRESS, "TFTP cannot ARP address" },
+ { PXENV_STATUS_TFTP_OPEN_TIMEOUT, "TFTP open timeout" },
+ { PXENV_STATUS_TFTP_UNKNOWN_OPCODE, "TFTP unknown opcode" },
+ { PXENV_STATUS_TFTP_READ_TIMEOUT, "TFTP read timeout" },
+ { PXENV_STATUS_TFTP_ERROR_OPCODE, "TFTP error opcode" },
+ { PXENV_STATUS_TFTP_CANNOT_OPEN_CONNECTION,
+ "TFTP cannot open connection" },
+ { PXENV_STATUS_TFTP_CANNOT_READ_FROM_CONNECTION,
+ "TFTP cannot read from connection" },
+ { PXENV_STATUS_TFTP_TOO_MANY_PACKAGES, "TFTP too many packages" },
+ { PXENV_STATUS_TFTP_FILE_NOT_FOUND, "TFTP file not found" },
+ { PXENV_STATUS_TFTP_ACCESS_VIOLATION, "TFTP access violation" },
+ { PXENV_STATUS_TFTP_NO_MCAST_ADDRESS, "TFTP no mcast address" },
+ { PXENV_STATUS_TFTP_NO_FILESIZE, "TFTP no filesize" },
+ { PXENV_STATUS_TFTP_INVALID_PACKET_SIZE, "TFTP invalid packet size" },
+ { PXENV_STATUS_DHCP_TIMEOUT, "DHCP timeout" },
+ { PXENV_STATUS_DHCP_NO_IP_ADDRESS, "DHCP no ip address" },
+ { PXENV_STATUS_DHCP_NO_BOOTFILE_NAME, "DHCP no bootfile name" },
+ { PXENV_STATUS_DHCP_BAD_IP_ADDRESS, "DHCP bad ip address" },
+ { PXENV_STATUS_UNDI_INVALID_FUNCTION, "UNDI invalid function" },
+ { PXENV_STATUS_UNDI_MEDIATEST_FAILED, "UNDI mediatest failed" },
+ { PXENV_STATUS_UNDI_CANNOT_INIT_NIC_FOR_MCAST,
+ "UNDI cannot initialise NIC for multicast" },
+ { PXENV_STATUS_UNDI_CANNOT_INITIALIZE_NIC,
+ "UNDI cannot initialise NIC" },
+ { PXENV_STATUS_UNDI_CANNOT_INITIALIZE_PHY,
+ "UNDI cannot initialise PHY" },
+ { PXENV_STATUS_UNDI_CANNOT_READ_CONFIG_DATA,
+ "UNDI cannot read config data" },
+ { PXENV_STATUS_UNDI_CANNOT_READ_INIT_DATA,
+ "UNDI cannot read init data" },
+ { PXENV_STATUS_UNDI_BAD_MAC_ADDRESS, "UNDI bad MAC address" },
+ { PXENV_STATUS_UNDI_BAD_EEPROM_CHECKSUM, "UNDI bad EEPROM checksum" },
+ { PXENV_STATUS_UNDI_ERROR_SETTING_ISR, "UNDI error setting ISR" },
+ { PXENV_STATUS_UNDI_INVALID_STATE, "UNDI invalid state" },
+ { PXENV_STATUS_UNDI_TRANSMIT_ERROR, "UNDI transmit error" },
+ { PXENV_STATUS_UNDI_INVALID_PARAMETER, "UNDI invalid parameter" },
+ { PXENV_STATUS_BSTRAP_PROMPT_MENU, "Bootstrap prompt menu" },
+ { PXENV_STATUS_BSTRAP_MCAST_ADDR, "Bootstrap mcast addr" },
+ { PXENV_STATUS_BSTRAP_MISSING_LIST, "Bootstrap missing list" },
+ { PXENV_STATUS_BSTRAP_NO_RESPONSE, "Bootstrap no response" },
+ { PXENV_STATUS_BSTRAP_FILE_TOO_BIG, "Bootstrap file too big" },
+ { PXENV_STATUS_BINL_CANCELED_BY_KEYSTROKE,
+ "BINL canceled by keystroke" },
+ { PXENV_STATUS_BINL_NO_PXE_SERVER, "BINL no PXE server" },
+ { PXENV_STATUS_NOT_AVAILABLE_IN_PMODE,
+ "Not available in protected mode" },
+ { PXENV_STATUS_NOT_AVAILABLE_IN_RMODE, "Not available in real mode" },
+ { PXENV_STATUS_BUSD_DEVICE_NOT_SUPPORTED,
+ "BUSD device not supported" },
+ { PXENV_STATUS_LOADER_NO_FREE_BASE_MEMORY,
+ "Loader no free base memory" },
+ { PXENV_STATUS_LOADER_NO_BC_ROMID, "Loader no Base Code ROM ID" },
+ { PXENV_STATUS_LOADER_BAD_BC_ROMID, "Loader bad Base Code ROM ID" },
+ { PXENV_STATUS_LOADER_BAD_BC_RUNTIME_IMAGE,
+ "Loader bad Base Code runtime image" },
+ { PXENV_STATUS_LOADER_NO_UNDI_ROMID, "Loader no UNDI ROM ID" },
+ { PXENV_STATUS_LOADER_BAD_UNDI_ROMID, "Loader bad UNDI ROM ID" },
+ { PXENV_STATUS_LOADER_BAD_UNDI_DRIVER_IMAGE,
+ "Loader bad UNDI driver image" },
+ { PXENV_STATUS_LOADER_NO_PXE_STRUCT, "Loader no !PXE struct" },
+ { PXENV_STATUS_LOADER_NO_PXENV_STRUCT, "Loader no PXENV+ struct" },
+ { PXENV_STATUS_LOADER_UNDI_START, "Loader UNDI start" },
+ { PXENV_STATUS_LOADER_BC_START, "Loader Base Code start" },
+};
diff --git a/src/interface/pxe/pxe_loader.c b/src/interface/pxe/pxe_loader.c
new file mode 100644
index 000000000..2539aaeb0
--- /dev/null
+++ b/src/interface/pxe/pxe_loader.c
@@ -0,0 +1,83 @@
+/** @file
+ *
+ * PXE UNDI loader
+ *
+ */
+
+/*
+ * Copyright (C) 2004 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * 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.
+ */
+
+#include "pxe.h"
+
+/* PXENV_UNDI_LOADER
+ *
+ * Status: working
+ *
+ * NOTE: This is not a genuine PXE API call; the loader has a separate
+ * entry point. However, to simplify the mapping of the PXE API to
+ * the internal Etherboot API, both are directed through the same
+ * interface.
+ */
+PXENV_EXIT_t undi_loader ( struct s_UNDI_LOADER *undi_loader ) {
+ uint32_t loader_phys = virt_to_phys ( undi_loader );
+
+ DBG ( "PXENV_UNDI_LOADER" );
+
+ /* Set UNDI DS as our real-mode stack */
+ use_undi_ds_for_rm_stack ( undi_loader->undi_ds );
+
+ /* FIXME: These lines are borrowed from main.c. There should
+ * probably be a single initialise() function that does all
+ * this, but it's currently split interestingly between main()
+ * and main_loop()...
+ */
+
+
+ /* CHECKME: Our init functions have probably already been
+ called by the ROM prefix's call to setup(), haven't
+ they? */
+
+
+
+ /* We have relocated; the loader pointer is now invalid */
+ undi_loader = phys_to_virt ( loader_phys );
+
+ /* Install PXE stack to area specified by NBP */
+ install_pxe_stack ( VIRTUAL ( undi_loader->undi_cs, 0 ) );
+
+ /* Call pxenv_start_undi to set parameters. Why the hell PXE
+ * requires these parameters to be provided twice is beyond
+ * the wit of any sane man. Don't worry if it fails; the NBP
+ * should call PXENV_START_UNDI separately anyway.
+ */
+ pxenv_start_undi ( &undi_loader->u.start_undi );
+ /* Unhook stack; the loader is not meant to hook int 1a etc,
+ * but the call the pxenv_start_undi will cause it to happen.
+ */
+
+ /* FIXME: can't use ENSURE_CAN_UNLOAD() thanks to newer gcc's
+ * barfing on unnamed struct/unions. */
+ /* ENSURE_CAN_UNLOAD ( undi_loader ); */
+
+ /* Fill in addresses of !PXE and PXENV+ structures */
+ PTR_TO_SEGOFF16 ( &pxe_stack->pxe, undi_loader->pxe_ptr );
+ PTR_TO_SEGOFF16 ( &pxe_stack->pxenv, undi_loader->pxenv_ptr );
+
+ undi_loader->u.Status = PXENV_STATUS_SUCCESS;
+ return PXENV_EXIT_SUCCESS;
+}
diff --git a/src/interface/pxe/pxe_preboot.c b/src/interface/pxe/pxe_preboot.c
new file mode 100644
index 000000000..f0e12bbb9
--- /dev/null
+++ b/src/interface/pxe/pxe_preboot.c
@@ -0,0 +1,249 @@
+/** @file
+ *
+ * PXE Preboot API
+ *
+ */
+
+/* PXE API interface for Etherboot.
+ *
+ * Copyright (C) 2004 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * 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.
+ */
+
+#include "pxe.h"
+#include "pxe_callbacks.h"
+
+/**
+ * UNLOAD BASE CODE STACK
+ *
+ * @v None -
+ * @ret ...
+ *
+ */
+PXENV_EXIT_t pxenv_unload_stack ( struct s_PXENV_UNLOAD_STACK *unload_stack ) {
+ int success;
+
+ DBG ( "PXENV_UNLOAD_STACK" );
+ success = ensure_pxe_state ( CAN_UNLOAD );
+
+ /* We need to call cleanup() at some point. The network card
+ * has already been disabled by ENSURE_CAN_UNLOAD(), but for
+ * the sake of completeness we should call the console_fini()
+ * etc. that are part of cleanup().
+ *
+ * There seems to be a lack of consensus on which is the final
+ * PXE API call to make, but it's a fairly safe bet that all
+ * the potential shutdown sequences will include a call to
+ * PXENV_UNLOAD_STACK at some point, so we may as well do it
+ * here.
+ */
+ cleanup();
+
+ if ( ! success ) {
+ unload_stack->Status = PXENV_STATUS_KEEP_ALL;
+ return PXENV_EXIT_FAILURE;
+ }
+
+ unload_stack->Status = PXENV_STATUS_SUCCESS;
+ return PXENV_EXIT_SUCCESS;
+}
+
+/* PXENV_GET_CACHED_INFO
+ *
+ * Status: working
+ */
+PXENV_EXIT_t pxenv_get_cached_info ( struct s_PXENV_GET_CACHED_INFO
+ *get_cached_info ) {
+ BOOTPLAYER_t *cached_info = &pxe_stack->cached_info;
+ DBG ( "PXENV_GET_CACHED_INFO %d", get_cached_info->PacketType );
+ ENSURE_READY ( get_cached_info );
+
+ /* Fill in cached_info structure in our pxe_stack */
+
+ /* I don't think there's actually any way we can be called in
+ * the middle of a DHCP request...
+ */
+ cached_info->opcode = BOOTP_REP;
+ /* We only have Ethernet drivers */
+ cached_info->Hardware = ETHER_TYPE;
+ cached_info->Hardlen = ETH_ALEN;
+ /* PXESPEC: "Client sets" says the spec, but who's filling in
+ * this structure? It ain't the client.
+ */
+ cached_info->Gatehops = 0;
+ cached_info->ident = 0;
+ cached_info->seconds = 0;
+ cached_info->Flags = BOOTP_BCAST;
+ /* PXESPEC: What do 'Client' and 'Your' IP address refer to? */
+ cached_info->cip = arptable[ARP_CLIENT].ipaddr.s_addr;
+ cached_info->yip = arptable[ARP_CLIENT].ipaddr.s_addr;
+ cached_info->sip = arptable[ARP_SERVER].ipaddr.s_addr;
+ /* PXESPEC: Does "GIP" mean "Gateway" or "Relay agent"? */
+ cached_info->gip = arptable[ARP_GATEWAY].ipaddr.s_addr;
+ memcpy ( cached_info->CAddr, arptable[ARP_CLIENT].node, ETH_ALEN );
+ /* Nullify server name */
+ cached_info->Sname[0] = '\0';
+ memcpy ( cached_info->bootfile, KERNEL_BUF,
+ sizeof(cached_info->bootfile) );
+ /* Copy DHCP vendor options */
+ memcpy ( &cached_info->vendor.d, bootp_data.bootp_reply.bp_vend,
+ sizeof(cached_info->vendor.d) );
+
+ /* Copy to user-specified buffer, or set pointer to our buffer */
+ get_cached_info->BufferLimit = sizeof(*cached_info);
+ /* PXESPEC: says to test for Buffer == NULL *and* BufferSize =
+ * 0, but what are we supposed to do with a null buffer of
+ * non-zero size?!
+ */
+ if ( IS_NULL_SEGOFF16 ( get_cached_info->Buffer ) ) {
+ /* Point back to our buffer */
+ PTR_TO_SEGOFF16 ( cached_info, get_cached_info->Buffer );
+ get_cached_info->BufferSize = sizeof(*cached_info);
+ } else {
+ /* Copy to user buffer */
+ size_t size = sizeof(*cached_info);
+ void *buffer = SEGOFF16_TO_PTR ( get_cached_info->Buffer );
+ if ( get_cached_info->BufferSize < size )
+ size = get_cached_info->BufferSize;
+ DBG ( " to %x", virt_to_phys ( buffer ) );
+ memcpy ( buffer, cached_info, size );
+ /* PXESPEC: Should we return an error if the user
+ * buffer is too small? We do return the actual size
+ * of the buffer via BufferLimit, so the user does
+ * have a way to detect this already.
+ */
+ }
+
+ get_cached_info->Status = PXENV_STATUS_SUCCESS;
+ return PXENV_EXIT_SUCCESS;
+}
+
+/* PXENV_RESTART_TFTP
+ *
+ * Status: working
+ */
+PXENV_EXIT_t pxenv_restart_tftp ( struct s_PXENV_TFTP_READ_FILE
+ *restart_tftp ) {
+ PXENV_EXIT_t tftp_exit;
+
+ DBG ( "PXENV_RESTART_TFTP" );
+ ENSURE_READY ( restart_tftp );
+
+ /* Words cannot describe the complete mismatch between the PXE
+ * specification and any possible version of reality...
+ */
+ restart_tftp->Buffer = PXE_LOAD_ADDRESS; /* Fixed by spec, apparently */
+ restart_tftp->BufferSize = get_free_base_memory() - PXE_LOAD_ADDRESS; /* Near enough */
+ DBG ( "(" );
+ tftp_exit = pxe_api_call ( PXENV_TFTP_READ_FILE, (union u_PXENV_ANY*)restart_tftp );
+ DBG ( ")" );
+ if ( tftp_exit != PXENV_EXIT_SUCCESS ) return tftp_exit;
+
+ /* Fire up the new NBP */
+ restart_tftp->Status = xstartpxe();
+
+ /* Not sure what "SUCCESS" actually means, since we can only
+ * return if the new NBP failed to boot...
+ */
+ return PXENV_EXIT_SUCCESS;
+}
+
+/* PXENV_START_UNDI
+ *
+ * Status: working
+ */
+PXENV_EXIT_t pxenv_start_undi ( struct s_PXENV_START_UNDI *start_undi ) {
+ unsigned char bus, devfn;
+
+ DBG ( "PXENV_START_UNDI" );
+ ENSURE_MIDWAY(start_undi);
+
+ /* Record PCI bus & devfn passed by caller, so we know which
+ * NIC they want to use.
+ *
+ * If they don't match our already-existing NIC structure, set
+ * values to ensure that the specified NIC is used at the next
+ * call to pxe_intialise_nic().
+ */
+ bus = ( start_undi->AX >> 8 ) & 0xff;
+ devfn = start_undi->AX & 0xff;
+
+#warning "device probing mechanism has completely changed"
+#if 0
+ if ( ( pci->dev.driver == NULL ) ||
+ ( pci->dev.bus != bus ) || ( pci->dev.devfn != devfn ) ) {
+ /* This is quite a bit of a hack and relies on
+ * knowledge of the internal operation of Etherboot's
+ * probe mechanism.
+ */
+ DBG ( " set PCI %hhx:%hhx.%hhx",
+ bus, PCI_SLOT(devfn), PCI_FUNC(devfn) );
+ dev->type = BOOT_NIC;
+ dev->to_probe = PROBE_PCI;
+ memset ( &dev->state, 0, sizeof(dev->state) );
+ pci->advance = 1;
+ pci->dev.use_specified = 1;
+ pci->dev.bus = bus;
+ pci->dev.devfn = devfn;
+ }
+#endif
+
+ start_undi->Status = PXENV_STATUS_SUCCESS;
+ return PXENV_EXIT_SUCCESS;
+}
+
+/* PXENV_STOP_UNDI
+ *
+ * Status: working
+ */
+PXENV_EXIT_t pxenv_stop_undi ( struct s_PXENV_STOP_UNDI *stop_undi ) {
+ DBG ( "PXENV_STOP_UNDI" );
+
+ if ( ! ensure_pxe_state(CAN_UNLOAD) ) {
+ stop_undi->Status = PXENV_STATUS_KEEP_UNDI;
+ return PXENV_EXIT_FAILURE;
+ }
+
+ stop_undi->Status = PXENV_STATUS_SUCCESS;
+ return PXENV_EXIT_SUCCESS;
+}
+
+/* PXENV_START_BASE
+ *
+ * Status: won't implement (requires major structural changes)
+ */
+PXENV_EXIT_t pxenv_start_base ( struct s_PXENV_START_BASE *start_base ) {
+ DBG ( "PXENV_START_BASE" );
+ /* ENSURE_READY ( start_base ); */
+ start_base->Status = PXENV_STATUS_UNSUPPORTED;
+ return PXENV_EXIT_FAILURE;
+}
+
+/* PXENV_STOP_BASE
+ *
+ * Status: working
+ */
+PXENV_EXIT_t pxenv_stop_base ( struct s_PXENV_STOP_BASE *stop_base ) {
+ DBG ( "PXENV_STOP_BASE" );
+
+ /* The only time we will be called is when the NBP is trying
+ * to shut down the PXE stack. There's nothing we need to do
+ * in this call.
+ */
+
+ stop_base->Status = PXENV_STATUS_SUCCESS;
+ return PXENV_EXIT_SUCCESS;
+}
diff --git a/src/interface/pxe/pxe_tftp.c b/src/interface/pxe/pxe_tftp.c
new file mode 100644
index 000000000..2d824e11b
--- /dev/null
+++ b/src/interface/pxe/pxe_tftp.c
@@ -0,0 +1,623 @@
+/** @file
+ *
+ * PXE TFTP API
+ *
+ */
+
+/*
+ * Copyright (C) 2004 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * 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.
+ */
+
+#include "pxe.h"
+
+static int pxe_tftp_read_block ( unsigned char *data, unsigned int block,
+ unsigned int len, int eof );
+
+/**
+ * TFTP OPEN
+ *
+ * @v tftp_open Pointer to a struct s_PXENV_TFTP_OPEN
+ * @v s_PXENV_TFTP_OPEN::ServerIPAddress TFTP server IP address
+ * @v s_PXENV_TFTP_OPEN::GatewayIPAddress Relay agent IP address, or 0.0.0.0
+ * @v s_PXENV_TFTP_OPEN::FileName Name of file to open
+ * @v s_PXENV_TFTP_OPEN::TFTPPort TFTP server UDP port
+ * @v s_PXENV_TFTP_OPEN::PacketSize TFTP blksize option to request
+ * @ret #PXENV_EXIT_SUCCESS File was opened
+ * @ret #PXENV_EXIT_FAILURE File was not opened
+ * @ret s_PXENV_TFTP_OPEN::Status PXE status code
+ * @ret s_PXENV_TFTP_OPEN::PacketSize Negotiated blksize
+ * @err #PXENV_STATUS_TFTP_INVALID_PACKET_SIZE Requested blksize too small
+ *
+ * Opens a TFTP connection for downloading a file a block at a time
+ * using pxenv_tftp_read().
+ *
+ * If s_PXENV_TFTP_OPEN::GatewayIPAddress is 0.0.0.0, normal IP
+ * routing will take place. See the relevant
+ * @ref pxe_routing "implementation note" for more details.
+ *
+ * The blksize negotiated with the TFTP server will be returned in
+ * s_PXENV_TFTP_OPEN::PacketSize, and will be the size of data blocks
+ * returned by subsequent calls to pxenv_tftp_read(). The TFTP server
+ * may negotiate a smaller blksize than the caller requested.
+ *
+ * Some TFTP servers do not support TFTP options, and will therefore
+ * not be able to use anything other than a fixed 512-byte blksize.
+ * The PXE specification version 2.1 requires that the caller must
+ * pass in s_PXENV_TFTP_OPEN::PacketSize with a value of 512 or
+ * greater.
+ *
+ * You can only have one TFTP connection open at a time, because the
+ * PXE API requires the PXE stack to keep state (e.g. local and remote
+ * port numbers, data block index) about the open TFTP connection,
+ * rather than letting the caller do so.
+ *
+ * It is unclear precisely what constitutes a "TFTP open" operation.
+ * Clearly, we must send the TFTP open request to the server. Since
+ * we must know whether or not the open succeeded, we must wait for
+ * the first reply packet from the TFTP server. If the TFTP server
+ * supports options, the first reply packet will be an OACK; otherwise
+ * it will be a DATA packet. In other words, we may only get to
+ * discover whether or not the open succeeded when we receive the
+ * first block of data. However, the pxenv_tftp_open() API provides
+ * no way for us to return this block of data at this time. See the
+ * relevant @ref pxe_note_tftp "implementation note" for Etherboot's
+ * solution to this problem.
+ *
+ * On x86, you must set the s_PXE::StatusCallout field to a nonzero
+ * value before calling this function in protected mode. You cannot
+ * call this function with a 32-bit stack segment. (See the relevant
+ * @ref pxe_x86_pmode16 "implementation note" for more details.)
+ *
+ * @note If you pass in a value less than 512 for
+ * s_PXENV_TFTP_OPEN::PacketSize, Etherboot will attempt to negotiate
+ * this blksize with the TFTP server, even though such a value is not
+ * permitted according to the PXE specification. If the TFTP server
+ * ends up dictating a blksize larger than the value requested by the
+ * caller (which is very probable in the case of a requested blksize
+ * less than 512), then Etherboot will return the error
+ * #PXENV_STATUS_TFTP_INVALID_PACKET_SIZE.
+ *
+ * @note According to the PXE specification version 2.1, this call
+ * "opens a file for reading/writing", though how writing is to be
+ * achieved without the existence of an API call %pxenv_tftp_write()
+ * is not made clear.
+ *
+ * @note Despite the existence of the numerous statements within the
+ * PXE specification of the form "...if a TFTP/MTFTP or UDP connection
+ * is active...", you cannot use pxenv_tftp_open() and
+ * pxenv_tftp_read() to read a file via MTFTP; only via plain old
+ * TFTP. If you want to use MTFTP, use pxenv_tftp_read_file()
+ * instead. Astute readers will note that, since
+ * pxenv_tftp_read_file() is an atomic operation from the point of
+ * view of the PXE API, it is conceptually impossible to issue any
+ * other PXE API call "if an MTFTP connection is active".
+ */
+PXENV_EXIT_t pxenv_tftp_open ( struct s_PXENV_TFTP_OPEN *tftp_open ) {
+ struct sockaddr_in tftp_server;
+ struct tftpreq_info_t request;
+ struct tftpblk_info_t block;
+
+ DBG ( "PXENV_TFTP_OPEN" );
+ ENSURE_READY ( tftp_open );
+
+ /* Set server address and port */
+ tftp_server.sin_addr.s_addr = tftp_open->ServerIPAddress
+ ? tftp_open->ServerIPAddress
+ : arptable[ARP_SERVER].ipaddr.s_addr;
+ tftp_server.sin_port = ntohs ( tftp_open->TFTPPort );
+#ifdef WORK_AROUND_BPBATCH_BUG
+ /* Force use of port 69; BpBatch tries to use port 4 for some
+ * bizarre reason. */
+ tftp_server.sin_port = TFTP_PORT;
+#endif
+ /* Ignore gateway address; we can route properly */
+ /* Fill in request structure */
+ request.server = &tftp_server;
+ request.name = tftp_open->FileName;
+ request.blksize = tftp_open->PacketSize;
+ DBG ( " %@:%d/%s (%d)", tftp_open->ServerIPAddress,
+ tftp_open->TFTPPort, request.name, request.blksize );
+ if ( !request.blksize ) request.blksize = TFTP_DEFAULT_BLKSIZE;
+ /* Make request and get first packet */
+ if ( !tftp_block ( &request, &block ) ) {
+ tftp_open->Status = PXENV_STATUS_TFTP_FILE_NOT_FOUND;
+ return PXENV_EXIT_FAILURE;
+ }
+ /* Fill in PacketSize */
+ tftp_open->PacketSize = request.blksize;
+ /* Store first block for later retrieval by TFTP_READ */
+ pxe_stack->tftpdata.magic_cookie = PXE_TFTP_MAGIC_COOKIE;
+ pxe_stack->tftpdata.len = block.len;
+ pxe_stack->tftpdata.eof = block.eof;
+ memcpy ( pxe_stack->tftpdata.data, block.data, block.len );
+
+ tftp_open->Status = PXENV_STATUS_SUCCESS;
+ return PXENV_EXIT_SUCCESS;
+}
+
+/**
+ * TFTP CLOSE
+ *
+ * @v tftp_close Pointer to a struct s_PXENV_TFTP_CLOSE
+ * @ret #PXENV_EXIT_SUCCESS File was closed successfully
+ * @ret #PXENV_EXIT_FAILURE File was not closed
+ * @ret s_PXENV_TFTP_CLOSE::Status PXE status code
+ * @err None -
+ *
+ * Close a connection previously opened with pxenv_tftp_open(). You
+ * must have previously opened a connection with pxenv_tftp_open().
+ *
+ * On x86, you must set the s_PXE::StatusCallout field to a nonzero
+ * value before calling this function in protected mode. You cannot
+ * call this function with a 32-bit stack segment. (See the relevant
+ * @ref pxe_x86_pmode16 "implementation note" for more details.)
+ *
+ * @note Since TFTP runs over UDP, which is a connectionless protocol,
+ * the concept of closing a file is somewhat meaningless. This call
+ * is a no-op for Etherboot.
+ */
+PXENV_EXIT_t pxenv_tftp_close ( struct s_PXENV_TFTP_CLOSE *tftp_close ) {
+ DBG ( "PXENV_TFTP_CLOSE" );
+ ENSURE_READY ( tftp_close );
+ tftp_close->Status = PXENV_STATUS_SUCCESS;
+ return PXENV_EXIT_SUCCESS;
+}
+
+/**
+ * TFTP READ
+ *
+ * @v tftp_read Pointer to a struct s_PXENV_TFTP_READ
+ * @v s_PXENV_TFTP_READ::Buffer Address of data buffer
+ * @ret #PXENV_EXIT_SUCCESS Data was read successfully
+ * @ret #PXENV_EXIT_FAILURE Data was not read
+ * @ret s_PXENV_TFTP_READ::Status PXE status code
+ * @ret s_PXENV_TFTP_READ::PacketNumber TFTP packet number
+ * @ret s_PXENV_TFTP_READ::BufferSize Length of data written into buffer
+ *
+ * Reads a single packet from a connection previously opened with
+ * pxenv_tftp_open() into the data buffer pointed to by
+ * s_PXENV_TFTP_READ::Buffer. You must have previously opened a
+ * connection with pxenv_tftp_open(). The data written into
+ * s_PXENV_TFTP_READ::Buffer is just the file data; the various
+ * network headers have already been removed.
+ *
+ * The buffer must be large enough to contain a packet of the size
+ * negotiated via the s_PXENV_TFTP_OPEN::PacketSize field in the
+ * pxenv_tftp_open() call. It is worth noting that the PXE
+ * specification does @b not require the caller to fill in
+ * s_PXENV_TFTP_READ::BufferSize before calling pxenv_tftp_read(), so
+ * the PXE stack is free to ignore whatever value the caller might
+ * place there and just assume that the buffer is large enough. That
+ * said, it may be worth the caller always filling in
+ * s_PXENV_TFTP_READ::BufferSize to guard against PXE stacks that
+ * mistake it for an input parameter.
+ *
+ * The length of the TFTP data packet will be returned via
+ * s_PXENV_TFTP_READ::BufferSize. If this length is less than the
+ * blksize negotiated via s_PXENV_TFTP_OPEN::PacketSize in the call to
+ * pxenv_tftp_open(), this indicates that the block is the last block
+ * in the file. Note that zero is a valid length for
+ * s_PXENV_TFTP_READ::BufferSize, and will occur when the length of
+ * the file is a multiple of the blksize.
+ *
+ * The PXE specification doesn't actually state that calls to
+ * pxenv_tftp_read() will return the data packets in strict sequential
+ * order, though most PXE stacks will probably do so. The sequence
+ * number of the packet will be returned in
+ * s_PXENV_TFTP_READ::PacketNumber. The first packet in the file has
+ * a sequence number of one, not zero.
+ *
+ * To guard against flawed PXE stacks, the caller should probably set
+ * s_PXENV_TFTP_READ::PacketNumber to one less than the expected
+ * returned value (i.e. set it to zero for the first call to
+ * pxenv_tftp_read() and then re-use the returned s_PXENV_TFTP_READ
+ * parameter block for subsequent calls without modifying
+ * s_PXENV_TFTP_READ::PacketNumber between calls). The caller should
+ * also guard against potential problems caused by flawed
+ * implementations returning the occasional duplicate packet, by
+ * checking that the value returned in s_PXENV_TFTP_READ::PacketNumber
+ * is as expected (i.e. one greater than that returned from the
+ * previous call to pxenv_tftp_read()).
+ *
+ * Nothing in the PXE specification indicates when the TFTP
+ * acknowledgement packets will be sent back to the server. See the
+ * relevant @ref pxe_note_tftp "implementation note" for details on
+ * when Etherboot chooses to send these packets.
+ *
+ * On x86, you must set the s_PXE::StatusCallout field to a nonzero
+ * value before calling this function in protected mode. You cannot
+ * call this function with a 32-bit stack segment. (See the relevant
+ * @ref pxe_x86_pmode16 "implementation note" for more details.)
+ */
+PXENV_EXIT_t pxenv_tftp_read ( struct s_PXENV_TFTP_READ *tftp_read ) {
+ struct tftpblk_info_t block;
+
+ DBG ( "PXENV_TFTP_READ" );
+ ENSURE_READY ( tftp_read );
+
+ /* Do we have a block pending */
+ if ( pxe_stack->tftpdata.magic_cookie == PXE_TFTP_MAGIC_COOKIE ) {
+ block.data = pxe_stack->tftpdata.data;
+ block.len = pxe_stack->tftpdata.len;
+ block.eof = pxe_stack->tftpdata.eof;
+ block.block = 1; /* Will be the first block */
+ pxe_stack->tftpdata.magic_cookie = 0;
+ } else {
+ if ( !tftp_block ( NULL, &block ) ) {
+ tftp_read->Status = PXENV_STATUS_TFTP_FILE_NOT_FOUND;
+ return PXENV_EXIT_FAILURE;
+ }
+ }
+
+ /* Return data */
+ tftp_read->PacketNumber = block.block;
+ tftp_read->BufferSize = block.len;
+ memcpy ( SEGOFF16_TO_PTR(tftp_read->Buffer), block.data, block.len );
+ DBG ( " %d to %hx:%hx", block.len, tftp_read->Buffer.segment,
+ tftp_read->Buffer.offset );
+
+ tftp_read->Status = PXENV_STATUS_SUCCESS;
+ return PXENV_EXIT_SUCCESS;
+}
+
+/**
+ * TFTP/MTFTP read file
+ *
+ * @v tftp_read_file Pointer to a struct s_PXENV_TFTP_READ_FILE
+ * @v s_PXENV_TFTP_READ_FILE::FileName File name
+ * @v s_PXENV_TFTP_READ_FILE::BufferSize Size of the receive buffer
+ * @v s_PXENV_TFTP_READ_FILE::Buffer Address of the receive buffer
+ * @v s_PXENV_TFTP_READ_FILE::ServerIPAddress TFTP server IP address
+ * @v s_PXENV_TFTP_READ_FILE::GatewayIPAddress Relay agent IP address
+ * @v s_PXENV_TFTP_READ_FILE::McastIPAddress File's multicast IP address
+ * @v s_PXENV_TFTP_READ_FILE::TFTPClntPort Client multicast UDP port
+ * @v s_PXENV_TFTP_READ_FILE::TFTPSrvPort Server multicast UDP port
+ * @v s_PXENV_TFTP_READ_FILE::TFTPOpenTimeOut Time to wait for first packet
+ * @v s_PXENV_TFTP_READ_FILE::TFTPReopenDelay MTFTP inactivity timeout
+ * @ret #PXENV_EXIT_SUCCESS File downloaded successfully
+ * @ret #PXENV_EXIT_FAILURE File not downloaded
+ * @ret s_PXENV_TFTP_READ_FILE::Status PXE status code
+ * @ret s_PXENV_TFTP_READ_FILE::BufferSize Length of downloaded file
+ *
+ * Downloads an entire file via either TFTP or MTFTP into the buffer
+ * pointed to by s_PXENV_TFTP_READ_FILE::Buffer.
+ *
+ * The PXE specification does not make it clear how the caller
+ * requests that MTFTP be used rather than TFTP (or vice versa). One
+ * reasonable guess is that setting
+ * s_PXENV_TFTP_READ_FILE::McastIPAddress to 0.0.0.0 would cause TFTP
+ * to be used instead of MTFTP, though it is conceivable that some PXE
+ * stacks would interpret that as "use the DHCP-provided multicast IP
+ * address" instead. Some PXE stacks will not implement MTFTP at all,
+ * and will always use TFTP.
+ *
+ * It is not specified whether or not
+ * s_PXENV_TFTP_READ_FILE::TFTPSrvPort will be used as the TFTP server
+ * port for TFTP (rather than MTFTP) downloads. Callers should assume
+ * that the only way to access a TFTP server on a non-standard port is
+ * to use pxenv_tftp_open() and pxenv_tftp_read().
+ *
+ * If s_PXENV_TFTP_READ_FILE::GatewayIPAddress is 0.0.0.0, normal IP
+ * routing will take place. See the relevant
+ * @ref pxe_routing "implementation note" for more details.
+ *
+ * It is interesting to note that s_PXENV_TFTP_READ_FILE::Buffer is an
+ * #ADDR32_t type, i.e. nominally a flat physical address. Some PXE
+ * NBPs (e.g. NTLDR) are known to call pxenv_tftp_read_file() in real
+ * mode with s_PXENV_TFTP_READ_FILE::Buffer set to an address above
+ * 1MB. This means that PXE stacks must be prepared to write to areas
+ * outside base memory. Exactly how this is to be achieved is not
+ * specified, though using INT 15,87 is as close to a standard method
+ * as any, and should probably be used. Switching to protected-mode
+ * in order to access high memory will fail if pxenv_tftp_read_file()
+ * is called in V86 mode; it is reasonably to expect that a V86
+ * monitor would intercept the relatively well-defined INT 15,87 if it
+ * wants the PXE stack to be able to write to high memory.
+ *
+ * Things get even more interesting if pxenv_tftp_read_file() is
+ * called in protected mode, because there is then absolutely no way
+ * for the PXE stack to write to an absolute physical address. You
+ * can't even get around the problem by creating a special "access
+ * everything" segment in the s_PXE data structure, because the
+ * #SEGDESC_t descriptors are limited to 64kB in size.
+ *
+ * Previous versions of the PXE specification (e.g. WfM 1.1a) provide
+ * a separate API call, %pxenv_tftp_read_file_pmode(), specifically to
+ * work around this problem. The s_PXENV_TFTP_READ_FILE_PMODE
+ * parameter block splits s_PXENV_TFTP_READ_FILE::Buffer into
+ * s_PXENV_TFTP_READ_FILE_PMODE::BufferSelector and
+ * s_PXENV_TFTP_READ_FILE_PMODE::BufferOffset, i.e. it provides a
+ * protected-mode segment:offset address for the data buffer. This
+ * API call is no longer present in version 2.1 of the PXE
+ * specification.
+ *
+ * Etherboot makes the assumption that s_PXENV_TFTP_READ_FILE::Buffer
+ * is an offset relative to the caller's data segment, when
+ * pxenv_tftp_read_file() is called in protected mode.
+ *
+ * On x86, you must set the s_PXE::StatusCallout field to a nonzero
+ * value before calling this function in protected mode. You cannot
+ * call this function with a 32-bit stack segment. (See the relevant
+ * @ref pxe_x86_pmode16 "implementation note" for more details.)
+ *
+ * @note Microsoft's NTLDR assumes that the filename passed in via
+ * s_PXENV_TFTP_READ_FILE::FileName will be stored in the "file" field
+ * of the stored DHCPACK packet, whence it will be returned via any
+ * subsequent calls to pxenv_get_cached_info(). Though this is
+ * essentially a bug in the Intel PXE implementation (not, for once,
+ * in the specification!), it is a bug that Microsoft relies upon, and
+ * so we implement this bug-for-bug compatibility by overwriting the
+ * filename stored DHCPACK packet with the filename passed in
+ * s_PXENV_TFTP_READ_FILE::FileName.
+ *
+ */
+PXENV_EXIT_t pxenv_tftp_read_file ( struct s_PXENV_TFTP_READ_FILE
+ *tftp_read_file ) {
+ struct sockaddr_in tftp_server;
+ int rc;
+
+ DBG ( "PXENV_TFTP_READ_FILE %s to [%x,%x)", tftp_read_file->FileName,
+ tftp_read_file->Buffer,
+ tftp_read_file->Buffer + tftp_read_file->BufferSize );
+ ENSURE_READY ( tftp_read_file );
+
+ /* inserted by Klaus Wittemeier */
+ /* KERNEL_BUF stores the name of the last required file */
+ /* This is a fix to make Microsoft Remote Install Services work (RIS) */
+ memcpy(KERNEL_BUF, tftp_read_file->FileName, sizeof(KERNEL_BUF));
+ /* end of insertion */
+
+ /* Set server address and port */
+ tftp_server.sin_addr.s_addr = tftp_read_file->ServerIPAddress
+ ? tftp_read_file->ServerIPAddress
+ : arptable[ARP_SERVER].ipaddr.s_addr;
+ tftp_server.sin_port = ntohs ( tftp_read_file->TFTPSrvPort );
+
+ pxe_stack->readfile.buffer = phys_to_virt ( tftp_read_file->Buffer );
+ pxe_stack->readfile.bufferlen = tftp_read_file->BufferSize;
+ pxe_stack->readfile.offset = 0;
+
+ rc = tftp ( NULL, &tftp_server, tftp_read_file->FileName,
+ pxe_tftp_read_block );
+ if ( rc ) {
+ tftp_read_file->Status = PXENV_STATUS_FAILURE;
+ return PXENV_EXIT_FAILURE;
+ }
+ tftp_read_file->Status = PXENV_STATUS_SUCCESS;
+ return PXENV_EXIT_SUCCESS;
+}
+
+static int pxe_tftp_read_block ( unsigned char *data,
+ unsigned int block __unused,
+ unsigned int len, int eof ) {
+ if ( pxe_stack->readfile.buffer ) {
+ if ( pxe_stack->readfile.offset + len >=
+ pxe_stack->readfile.bufferlen ) return -1;
+ memcpy ( pxe_stack->readfile.buffer +
+ pxe_stack->readfile.offset, data, len );
+ }
+ pxe_stack->readfile.offset += len;
+ return eof ? 0 : 1;
+}
+
+/**
+ * TFTP GET FILE SIZE
+ *
+ * @v tftp_get_fsize Pointer to a struct s_PXENV_TFTP_GET_FSIZE
+ * @v s_PXENV_TFTP_GET_FSIZE::ServerIPAddress TFTP server IP address
+ * @v s_PXENV_TFTP_GET_FSIZE::GatewayIPAddress Relay agent IP address
+ * @v s_PXENV_TFTP_GET_FSIZE::FileName File name
+ * @ret #PXENV_EXIT_SUCCESS File size was determined successfully
+ * @ret #PXENV_EXIT_FAILURE File size was not determined
+ * @ret s_PXENV_TFTP_GET_FSIZE::Status PXE status code
+ * @ret s_PXENV_TFTP_GET_FSIZE::FileSize File size
+ *
+ * Determine the size of a file on a TFTP server. This uses the
+ * "tsize" TFTP option, and so will not work with a TFTP server that
+ * does not support TFTP options, or that does not support the "tsize"
+ * option.
+ *
+ * The PXE specification states that this API call will @b not open a
+ * TFTP connection for subsequent use with pxenv_tftp_read(). (This
+ * is somewhat daft, since the only way to obtain the file size via
+ * the "tsize" option involves issuing a TFTP open request, but that's
+ * life.)
+ *
+ * You cannot call pxenv_tftp_get_fsize() while a TFTP or UDP
+ * connection is open.
+ *
+ * If s_PXENV_TFTP_GET_FSIZE::GatewayIPAddress is 0.0.0.0, normal IP
+ * routing will take place. See the relevant
+ * @ref pxe_routing "implementation note" for more details.
+ *
+ * On x86, you must set the s_PXE::StatusCallout field to a nonzero
+ * value before calling this function in protected mode. You cannot
+ * call this function with a 32-bit stack segment. (See the relevant
+ * @ref pxe_x86_pmode16 "implementation note" for more details.)
+ *
+ * @note There is no way to specify the TFTP server port with this API
+ * call. Though you can open a file using a non-standard TFTP server
+ * port (via s_PXENV_TFTP_OPEN::TFTPPort or, potentially,
+ * s_PXENV_TFTP_READ_FILE::TFTPSrvPort), you can only get the size of
+ * a file from a TFTP server listening on the standard TFTP port.
+ * "Consistency" is not a word in Intel's vocabulary.
+ */
+PXENV_EXIT_t pxenv_tftp_get_fsize ( struct s_PXENV_TFTP_GET_FSIZE
+ *tftp_get_fsize ) {
+ int rc;
+
+ DBG ( "PXENV_TFTP_GET_FSIZE" );
+ ENSURE_READY ( tftp_get_fsize );
+
+ pxe_stack->readfile.buffer = NULL;
+ pxe_stack->readfile.bufferlen = 0;
+ pxe_stack->readfile.offset = 0;
+
+#warning "Rewrite pxenv_tftp_get_fsize, please"
+ if ( rc ) {
+ tftp_get_fsize->FileSize = 0;
+ tftp_get_fsize->Status = PXENV_STATUS_FAILURE;
+ return PXENV_EXIT_FAILURE;
+ }
+ tftp_get_fsize->FileSize = pxe_stack->readfile.offset;
+ tftp_get_fsize->Status = PXENV_STATUS_SUCCESS;
+ return PXENV_EXIT_SUCCESS;
+}
+
+/** @page pxe_notes Etherboot PXE implementation notes
+
+@section pxe_note_tftp Welding together the TFTP protocol and the PXE TFTP API
+
+The PXE TFTP API is fundamentally poorly designed; the TFTP protocol
+simply does not map well into "open file", "read file block", "close
+file" operations. The problem is the unreliable nature of UDP
+transmissions and the lock-step mechanism employed by TFTP to
+guarantee file transfer. The lock-step mechanism requires that if we
+time out waiting for a packet to arrive, we must trigger its
+retransmission by retransmitting our own previously transmitted
+packet.
+
+For example, suppose that pxenv_tftp_read() is called to read the
+first data block of a file from a server that does not support TFTP
+options, and that no data block is received within the timeout period.
+In order to trigger the retransmission of this data block,
+pxenv_tftp_read() must retransmit the TFTP open request. However, the
+information used to build the TFTP open request is not available at
+this time; it was provided only to the pxenv_tftp_open() call. Even
+if we were able to retransmit a TFTP open request, we would have to
+allocate a new local port number (and be prepared for data to arrive
+from a new remote port number) in order to avoid violating the TFTP
+protocol specification.
+
+The question of when to transmit the ACK packets is also awkward. At
+a first glance, it would seem to be fairly simple: acknowledge a
+packet immediately after receiving it. However, since the ACK packet
+may itself be lost, the next call to pxenv_tftp_read() must be
+prepared to retransmit the acknowledgement.
+
+Another problem to consider is that the pxenv_tftp_open() API call
+must return an indication of whether or not the TFTP open request
+succeeded. In the case of a TFTP server that doesn't support TFTP
+options, the only indication of a successful open is the reception of
+the first data block. However, the pxenv_tftp_open() API provides no
+way to return this data block at this time.
+
+At least some PXE stacks (e.g. NILO) solve this problem by violating
+the TFTP protocol and never bothering with retransmissions, relying on
+the TFTP server to retransmit when it times out waiting for an ACK.
+This approach is dubious at best; if, for example, the initial TFTP
+open request is lost then NILO will believe that it has opened the
+file and will eventually time out and give up while waiting for the
+first packet to arrive.
+
+The only viable solution seems to be to allocate a buffer for the
+storage of the first data packet returned by the TFTP server, since we
+may receive this packet during the pxenv_tftp_open() call but have to
+return it from the subsequent pxenv_tftp_read() call. This buffer
+must be statically allocated and must be dedicated to providing a
+temporary home for TFTP packets. There is nothing in the PXE
+specification that prevents a caller from calling
+e.g. pxenv_undi_transmit() between calls to the TFTP API, so we cannot
+use the normal transmit/receive buffer for this purpose.
+
+Having paid the storage penalty for this buffer, we can then gain some
+simplicity by exploiting it in full. There is at least one
+circumstance (pxenv_tftp_open() called to open a file on a server that
+does not support TFTP options) in which we will have to enter
+pxenv_tftp_read() knowing that our previous transmission (the open
+request, in this situation) has already been acknowledged.
+Implementation of pxenv_tftp_read() can be made simpler by making this
+condition an invariant. Specifically, on each call to
+pxenv_tftp_read(), we shall ensure that the following are true:
+
+ - Our previous transmission has already been acknowledged. We
+ therefore do not need to keep state about our previous
+ transmission.
+
+ - The next packet to read is already in a buffer in memory.
+
+In order to maintain these two conditions, pxenv_tftp_read() must do
+the following:
+
+ - Copy the data packet from our buffer to the caller's buffer.
+
+ - Acknowledge the data packet that we have just copied. This will
+ trigger transmission of the next packet from the server.
+
+ - Retransmit this acknowledgement packet until the next packet
+ arrives.
+
+ - Copy the packet into our internal buffer, ready for the next call
+ to pxenv_tftp_read().
+
+It can be verified that this preserves the invariant condition, and it
+is clear that the resulting implementation of pxenv_tftp_read() can be
+relatively simple. (For the special case of the last data packet,
+pxenv_tftp_read() should return immediately after sending a single
+acknowledgement packet.)
+
+In order to set up this invariant condition for the first call to
+pxenv_tftp_read(), pxenv_tftp_open() must do the following:
+
+ - Construct and transmit the TFTP open request.
+
+ - Retransmit the TFTP open request (using a new local port number as
+ necessary) until a response (DATA, OACK, or ERROR) is received.
+
+ - If the response is an OACK, acknowledge the OACK and retransmit
+ the acknowledgement until the first DATA packet arrives.
+
+ - If we have a DATA packet, store it in a buffer ready for the first
+ call to pxenv_tftp_read().
+
+This approach has the advantage of being fully compliant with both
+RFC1350 (TFTP) and RFC2347 (TFTP options). It avoids unnecessary
+retransmissions. The cost is approximately 1500 bytes of
+uninitialised storage. Since there is demonstrably no way to avoid
+paying this cost without either violating the protocol specifications
+or introducing unnecessary retransmissions, we deem this to be a cost
+worth paying.
+
+A small performance gain may be obtained by adding a single extra
+"send ACK" in both pxenv_tftp_open() and pxenv_tftp_read() immediately
+after receiving the DATA packet and copying it into the internal
+buffer. The sequence of events for pxenv_tftp_read() then becomes:
+
+ - Copy the data packet from our buffer to the caller's buffer.
+
+ - If this was the last data packet, return immediately.
+
+ - Check to see if a TFTP data packet is waiting. If not, send an
+ ACK for the data packet that we have just copied, and retransmit
+ this ACK until the next data packet arrives.
+
+ - Copy the packet into our internal buffer, ready for the next call
+ to pxenv_tftp_read().
+
+ - Send a single ACK for this data packet.
+
+Sending the ACK at this point allows the server to transmit the next
+data block while our caller is processing the current packet. If this
+ACK is lost, or the DATA packet it triggers is lost or is consumed by
+something other than pxenv_tftp_read() (e.g. by calls to
+pxenv_undi_isr()), then the next call to pxenv_tftp_read() will not
+find a TFTP data packet waiting and will retransmit the ACK anyway.
+
+Note to future API designers at Intel: try to understand the
+underlying network protocol first!
+
+*/
diff --git a/src/interface/pxe/pxe_udp.c b/src/interface/pxe/pxe_udp.c
new file mode 100644
index 000000000..db5981b49
--- /dev/null
+++ b/src/interface/pxe/pxe_udp.c
@@ -0,0 +1,332 @@
+/** @file
+ *
+ * PXE UDP API
+ *
+ */
+
+#include "pxe.h"
+#include "io.h"
+#include "string.h"
+
+/*
+ * Copyright (C) 2004 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * 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.
+ */
+
+/**
+ * UDP OPEN
+ *
+ * @v udp_open Pointer to a struct s_PXENV_UDP_OPEN
+ * @v s_PXENV_UDP_OPEN::src_ip IP address of this station, or 0.0.0.0
+ * @ret #PXENV_EXIT_SUCCESS Always
+ * @ret s_PXENV_UDP_OPEN::Status PXE status code
+ * @err #PXENV_STATUS_UNDI_INVALID_STATE NIC could not be initialised
+ *
+ * Prepares the PXE stack for communication using pxenv_udp_write()
+ * and pxenv_udp_read().
+ *
+ * The IP address supplied in s_PXENV_UDP_OPEN::src_ip will be
+ * recorded and used as the local station's IP address for all further
+ * communication, including communication by means other than
+ * pxenv_udp_write() and pxenv_udp_read(). (If
+ * s_PXENV_UDP_OPEN::src_ip is 0.0.0.0, the local station's IP address
+ * will remain unchanged.)
+ *
+ * You can only have one open UDP connection at a time. You cannot
+ * have a UDP connection open at the same time as a TFTP connection.
+ * (This is not strictly true for Etherboot; see the relevant @ref
+ * pxe_note_udp "implementation note" for more details.)
+ *
+ * On x86, you must set the s_PXE::StatusCallout field to a nonzero
+ * value before calling this function in protected mode. You cannot
+ * call this function with a 32-bit stack segment. (See the relevant
+ * @ref pxe_x86_pmode16 "implementation note" for more details.)
+ *
+ * @note The PXE specification does not make it clear whether the IP
+ * address supplied in s_PXENV_UDP_OPEN::src_ip should be used only
+ * for this UDP connection, or retained for all future communication.
+ * The latter seems more consistent with typical PXE stack behaviour.
+ *
+ */
+PXENV_EXIT_t pxenv_udp_open ( struct s_PXENV_UDP_OPEN *udp_open ) {
+ DBG ( "PXENV_UDP_OPEN" );
+ ENSURE_READY ( udp_open );
+
+ if ( udp_open->src_ip &&
+ udp_open->src_ip != arptable[ARP_CLIENT].ipaddr.s_addr ) {
+ /* Overwrite our IP address */
+ DBG ( " with new IP %@", udp_open->src_ip );
+ arptable[ARP_CLIENT].ipaddr.s_addr = udp_open->src_ip;
+ }
+
+ udp_open->Status = PXENV_STATUS_SUCCESS;
+ return PXENV_EXIT_SUCCESS;
+}
+
+/**
+ * UDP CLOSE
+ *
+ * @v udp_close Pointer to a struct s_PXENV_UDP_CLOSE
+ * @ret #PXENV_EXIT_SUCCESS Always
+ * @ret s_PXENV_UDP_CLOSE::Status PXE status code
+ * @err None -
+ *
+ * Closes a UDP "connection" opened with pxenv_udp_open().
+ *
+ * You can only have one open UDP connection at a time. You cannot
+ * have a UDP connection open at the same time as a TFTP connection.
+ * You cannot use pxenv_udp_close() to close a TFTP connection; use
+ * pxenv_tftp_close() instead. (This is not strictly true for
+ * Etherboot; see the relevant @ref pxe_note_udp "implementation note"
+ * for more details.)
+ *
+ * On x86, you must set the s_PXE::StatusCallout field to a nonzero
+ * value before calling this function in protected mode. You cannot
+ * call this function with a 32-bit stack segment. (See the relevant
+ * @ref pxe_x86_pmode16 "implementation note" for more details.)
+ *
+ */
+PXENV_EXIT_t pxenv_udp_close ( struct s_PXENV_UDP_CLOSE *udp_close __unused ) {
+ DBG ( "PXENV_UDP_CLOSE" );
+ udp_close->Status = PXENV_STATUS_SUCCESS;
+ return PXENV_EXIT_SUCCESS;
+}
+
+/**
+ * UDP WRITE
+ *
+ * @v udp_write Pointer to a struct s_PXENV_UDP_WRITE
+ * @v s_PXENV_UDP_WRITE::ip Destination IP address
+ * @v s_PXENV_UDP_WRITE::gw Relay agent IP address, or 0.0.0.0
+ * @v s_PXENV_UDP_WRITE::src_port Source UDP port, or 0
+ * @v s_PXENV_UDP_WRITE::dst_port Destination UDP port
+ * @v s_PXENV_UDP_WRITE::buffer_size Length of the UDP payload
+ * @v s_PXENV_UDP_WRITE::buffer Address of the UDP payload
+ * @ret #PXENV_EXIT_SUCCESS Packet was transmitted successfully
+ * @ret #PXENV_EXIT_FAILURE Packet could not be transmitted
+ * @ret s_PXENV_UDP_WRITE::Status PXE status code
+ * @err #PXENV_STATUS_UNDI_INVALID_STATE NIC could not be initialised
+ * @err #PXENV_STATUS_OUT_OF_RESOURCES Packet was too large to transmit
+ * @err other Any error from pxenv_undi_transmit()
+ *
+ * Transmits a single UDP packet. A valid IP and UDP header will be
+ * prepended to the payload in s_PXENV_UDP_WRITE::buffer; the buffer
+ * should not contain precomputed IP and UDP headers, nor should it
+ * contain space allocated for these headers. The first byte of the
+ * buffer will be transmitted as the first byte following the UDP
+ * header.
+ *
+ * If s_PXENV_UDP_WRITE::gw is 0.0.0.0, normal IP routing will take
+ * place. See the relevant @ref pxe_routing "implementation note" for
+ * more details.
+ *
+ * If s_PXENV_UDP_WRITE::src_port is 0, port 2069 will be used.
+ *
+ * You must have opened a UDP connection with pxenv_udp_open() before
+ * calling pxenv_udp_write(). (This is not strictly true for
+ * Etherboot; see the relevant @ref pxe_note_udp "implementation note"
+ * for more details.)
+ *
+ * On x86, you must set the s_PXE::StatusCallout field to a nonzero
+ * value before calling this function in protected mode. You cannot
+ * call this function with a 32-bit stack segment. (See the relevant
+ * @ref pxe_x86_pmode16 "implementation note" for more details.)
+ *
+ */
+PXENV_EXIT_t pxenv_udp_write ( struct s_PXENV_UDP_WRITE *udp_write ) {
+ uint16_t src_port;
+ uint16_t dst_port;
+ struct udppacket *packet = (struct udppacket *)nic.packet;
+ int packet_size;
+
+ DBG ( "PXENV_UDP_WRITE" );
+ ENSURE_READY ( udp_write );
+
+ /* PXE spec says source port is 2069 if not specified */
+ src_port = ntohs(udp_write->src_port);
+ if ( src_port == 0 ) src_port = 2069;
+ dst_port = ntohs(udp_write->dst_port);
+ DBG ( " %d->%@:%d (%d)", src_port, udp_write->ip, dst_port,
+ udp_write->buffer_size );
+
+ /* FIXME: we ignore the gateway specified, since we're
+ * confident of being able to do our own routing. We should
+ * probably allow for multiple gateways.
+ */
+
+ /* Copy payload to packet buffer */
+ packet_size = ( (void*)&packet->payload - (void*)packet )
+ + udp_write->buffer_size;
+ if ( packet_size > ETH_FRAME_LEN ) {
+ udp_write->Status = PXENV_STATUS_OUT_OF_RESOURCES;
+ return PXENV_EXIT_FAILURE;
+ }
+ memcpy ( &packet->payload, SEGOFF16_TO_PTR(udp_write->buffer),
+ udp_write->buffer_size );
+
+ /* Transmit packet */
+ if ( ! udp_transmit ( udp_write->ip, src_port, dst_port,
+ packet_size, packet ) ) {
+ udp_write->Status = errno;
+ return PXENV_EXIT_FAILURE;
+ }
+
+ udp_write->Status = PXENV_STATUS_SUCCESS;
+ return PXENV_EXIT_SUCCESS;
+}
+
+/* Utility function for pxenv_udp_read() */
+static int await_pxe_udp ( int ival __unused, void *ptr,
+ unsigned short ptype __unused,
+ struct iphdr *ip, struct udphdr *udp,
+ struct tcphdr *tcp __unused ) {
+ struct s_PXENV_UDP_READ *udp_read = (struct s_PXENV_UDP_READ*)ptr;
+ uint16_t d_port;
+ size_t size;
+
+ /* Ignore non-UDP packets */
+ if ( !udp ) {
+ DBG ( " non-UDP" );
+ return 0;
+ }
+
+ /* Check dest_ip */
+ if ( udp_read->dest_ip && ( udp_read->dest_ip != ip->dest.s_addr ) ) {
+ DBG ( " wrong dest IP (got %@, wanted %@)",
+ ip->dest.s_addr, udp_read->dest_ip );
+ return 0;
+ }
+
+ /* Check dest_port */
+ d_port = ntohs ( udp_read->d_port );
+ if ( d_port && ( d_port != ntohs(udp->dest) ) ) {
+ DBG ( " wrong dest port (got %d, wanted %d)",
+ ntohs(udp->dest), d_port );
+ return 0;
+ }
+
+ /* Copy packet to buffer and fill in information */
+ udp_read->src_ip = ip->src.s_addr;
+ udp_read->s_port = udp->src; /* Both in network order */
+ size = ntohs(udp->len) - sizeof(*udp);
+ /* Workaround: NTLDR expects us to fill these in, even though
+ * PXESPEC clearly defines them as input parameters.
+ */
+ udp_read->dest_ip = ip->dest.s_addr;
+ udp_read->d_port = udp->dest;
+ DBG ( " %@:%d->%@:%d (%d)",
+ udp_read->src_ip, ntohs(udp_read->s_port),
+ udp_read->dest_ip, ntohs(udp_read->d_port), size );
+ if ( udp_read->buffer_size < size ) {
+ /* PXESPEC: what error code should we actually return? */
+ DBG ( " buffer too small (%d)", udp_read->buffer_size );
+ udp_read->Status = PXENV_STATUS_OUT_OF_RESOURCES;
+ return 0;
+ }
+ memcpy ( SEGOFF16_TO_PTR ( udp_read->buffer ), &udp->payload, size );
+ udp_read->buffer_size = size;
+
+ return 1;
+}
+
+/**
+ * UDP READ
+ *
+ * @v udp_read Pointer to a struct s_PXENV_UDP_READ
+ * @v s_PXENV_UDP_READ::dest_ip Destination IP address, or 0.0.0.0
+ * @v s_PXENV_UDP_READ::d_port Destination UDP port, or 0
+ * @v s_PXENV_UDP_READ::buffer_size Size of the UDP payload buffer
+ * @v s_PXENV_UDP_READ::buffer Address of the UDP payload buffer
+ * @ret #PXENV_EXIT_SUCCESS A packet has been received
+ * @ret #PXENV_EXIT_FAILURE No packet has been received
+ * @ret s_PXENV_UDP_READ::Status PXE status code
+ * @ret s_PXENV_UDP_READ::src_ip Source IP address
+ * @ret s_PXENV_UDP_READ::dest_ip Destination IP address
+ * @ret s_PXENV_UDP_READ::s_port Source UDP port
+ * @ret s_PXENV_UDP_READ::d_port Destination UDP port
+ * @ret s_PXENV_UDP_READ::buffer_size Length of UDP payload
+ * @err #PXENV_STATUS_UNDI_INVALID_STATE NIC could not be initialised
+ * @err #PXENV_STATUS_OUT_OF_RESOURCES Buffer was too small for payload
+ * @err #PXENV_STATUS_FAILURE No packet was ready to read
+ *
+ * Receive a single UDP packet. This is a non-blocking call; if no
+ * packet is ready to read, the call will return instantly with
+ * s_PXENV_UDP_READ::Status==PXENV_STATUS_FAILURE.
+ *
+ * If s_PXENV_UDP_READ::dest_ip is 0.0.0.0, UDP packets addressed to
+ * any IP address will be accepted and may be returned to the caller.
+ *
+ * If s_PXENV_UDP_READ::d_port is 0, UDP packets addressed to any UDP
+ * port will be accepted and may be returned to the caller.
+ *
+ * You must have opened a UDP connection with pxenv_udp_open() before
+ * calling pxenv_udp_read(). (This is not strictly true for
+ * Etherboot; see the relevant @ref pxe_note_udp "implementation note"
+ * for more details.)
+ *
+ * On x86, you must set the s_PXE::StatusCallout field to a nonzero
+ * value before calling this function in protected mode. You cannot
+ * call this function with a 32-bit stack segment. (See the relevant
+ * @ref pxe_x86_pmode16 "implementation note" for more details.)
+ *
+ * @note The PXE specification (version 2.1) does not state that we
+ * should fill in s_PXENV_UDP_READ::dest_ip and
+ * s_PXENV_UDP_READ::d_port, but Microsoft Windows' NTLDR program
+ * expects us to do so, and will fail if we don't.
+ *
+ */
+PXENV_EXIT_t pxenv_udp_read ( struct s_PXENV_UDP_READ *udp_read ) {
+ DBG ( "PXENV_UDP_READ" );
+ ENSURE_READY ( udp_read );
+
+ /* Use await_reply with a timeout of zero */
+ /* Allow await_reply to change Status if necessary */
+ udp_read->Status = PXENV_STATUS_FAILURE;
+ if ( ! await_reply ( await_pxe_udp, 0, udp_read, 0 ) ) {
+ return PXENV_EXIT_FAILURE;
+ }
+
+ udp_read->Status = PXENV_STATUS_SUCCESS;
+ return PXENV_EXIT_SUCCESS;
+}
+
+/** @page pxe_notes Etherboot PXE implementation notes
+
+@section pxe_note_udp The connectionless nature of UDP
+
+The PXE specification states that it is possible to have only one open
+UDP or TFTP connection at any one time. Etherboot does not
+rigourously enforce this restriction, on the UNIX principle that the
+code should not prevent the user from doing stupid things, because
+that would also prevent the user from doing clever things. Since UDP
+is a connectionless protocol, it is perfectly possible to have
+multiple concurrent UDP "connections" open, provided that you take the
+multiplicity of connections into account when calling
+pxenv_udp_read(). Similarly, there is no technical reason that
+prevents you from calling pxenv_udp_write() in the middle of a TFTP
+download.
+
+Etherboot will therefore never return error codes indicating "a
+connection is already open", such as #PXENV_STATUS_UDP_OPEN. If you
+want to have multiple concurrent connections, go for it (but don't
+expect your perfectly sensible code to work with any other PXE stack).
+
+Since Etherboot treats UDP as the connectionless protocol that it
+really is, pxenv_udp_close() is actually a no-op, and there is no need
+to call pxenv_udp_open() before using pxenv_udp_write() or
+pxenv_udp_read().
+
+*/
diff --git a/src/interface/pxe/pxe_undi.c b/src/interface/pxe/pxe_undi.c
new file mode 100644
index 000000000..3919915bd
--- /dev/null
+++ b/src/interface/pxe/pxe_undi.c
@@ -0,0 +1,538 @@
+/** @file
+ *
+ * PXE UNDI API
+ *
+ */
+
+/*
+ * Copyright (C) 2004 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * 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.
+ */
+
+#include "pxe.h"
+
+typedef struct {
+ char dest[ETH_ALEN];
+ char source[ETH_ALEN];
+ uint16_t nstype;
+} media_header_t;
+
+static const char broadcast_mac[] = { 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF };
+
+/* PXENV_UNDI_STARTUP
+ *
+ * Status: working
+ */
+PXENV_EXIT_t pxenv_undi_startup ( struct s_PXENV_UNDI_STARTUP *undi_startup ) {
+ DBG ( "PXENV_UNDI_STARTUP" );
+ ENSURE_MIDWAY(undi_startup);
+
+ undi_startup->Status = PXENV_STATUS_SUCCESS;
+ return PXENV_EXIT_SUCCESS;
+}
+
+/* PXENV_UNDI_CLEANUP
+ *
+ * Status: working
+ */
+PXENV_EXIT_t pxenv_undi_cleanup ( struct s_PXENV_UNDI_CLEANUP *undi_cleanup ) {
+ DBG ( "PXENV_UNDI_CLEANUP" );
+ ENSURE_CAN_UNLOAD ( undi_cleanup );
+
+ undi_cleanup->Status = PXENV_STATUS_SUCCESS;
+ return PXENV_EXIT_SUCCESS;
+}
+
+/* PXENV_UNDI_INITIALIZE
+ *
+ * Status: working
+ */
+PXENV_EXIT_t pxenv_undi_initialize ( struct s_PXENV_UNDI_INITIALIZE
+ *undi_initialize ) {
+ DBG ( "PXENV_UNDI_INITIALIZE" );
+ ENSURE_MIDWAY ( undi_initialize );
+
+ undi_initialize->Status = PXENV_STATUS_SUCCESS;
+ return PXENV_EXIT_SUCCESS;
+}
+
+/* PXENV_UNDI_RESET_ADAPTER
+ *
+ * Status: working
+ */
+PXENV_EXIT_t pxenv_undi_reset_adapter ( struct s_PXENV_UNDI_RESET
+ *undi_reset_adapter ) {
+ DBG ( "PXENV_UNDI_RESET_ADAPTER" );
+
+ ENSURE_MIDWAY ( undi_reset_adapter );
+ ENSURE_READY ( undi_reset_adapter );
+
+ undi_reset_adapter->Status = PXENV_STATUS_SUCCESS;
+ return PXENV_EXIT_SUCCESS;
+}
+
+/* PXENV_UNDI_SHUTDOWN
+ *
+ * Status: working
+ */
+PXENV_EXIT_t pxenv_undi_shutdown ( struct s_PXENV_UNDI_SHUTDOWN
+ *undi_shutdown ) {
+ DBG ( "PXENV_UNDI_SHUTDOWN" );
+ ENSURE_MIDWAY ( undi_shutdown );
+
+ undi_shutdown->Status = PXENV_STATUS_SUCCESS;
+ return PXENV_EXIT_SUCCESS;
+}
+
+/* PXENV_UNDI_OPEN
+ *
+ * Status: working
+ */
+PXENV_EXIT_t pxenv_undi_open ( struct s_PXENV_UNDI_OPEN *undi_open ) {
+ DBG ( "PXENV_UNDI_OPEN" );
+ ENSURE_READY ( undi_open );
+
+ /* PXESPEC: This is where we choose to enable interrupts.
+ * Can't actually find where we're meant to in the PXE spec,
+ * but this should work.
+ */
+ eth_irq ( ENABLE );
+
+ undi_open->Status = PXENV_STATUS_SUCCESS;
+ return PXENV_EXIT_SUCCESS;
+}
+
+/* PXENV_UNDI_CLOSE
+ *
+ * Status: working
+ */
+PXENV_EXIT_t pxenv_undi_close ( struct s_PXENV_UNDI_CLOSE *undi_close ) {
+ DBG ( "PXENV_UNDI_CLOSE" );
+ ENSURE_MIDWAY ( undi_close );
+
+ undi_close->Status = PXENV_STATUS_SUCCESS;
+ return PXENV_EXIT_SUCCESS;
+}
+
+/* PXENV_UNDI_TRANSMIT
+ *
+ * Status: working
+ */
+PXENV_EXIT_t pxenv_undi_transmit ( struct s_PXENV_UNDI_TRANSMIT
+ *undi_transmit ) {
+ struct s_PXENV_UNDI_TBD *tbd;
+ const char *dest;
+ unsigned int type;
+ unsigned int length;
+ const char *data;
+ media_header_t *media_header;
+
+ DBG ( "PXENV_UNDI_TRANSMIT" );
+ ENSURE_READY ( undi_transmit );
+
+ /* We support only the "immediate" portion of the TBD. Who
+ * knows what Intel's "engineers" were smoking when they came
+ * up with the array of transmit data blocks...
+ */
+ tbd = SEGOFF16_TO_PTR ( undi_transmit->TBD );
+ if ( tbd->DataBlkCount > 0 ) {
+ undi_transmit->Status = PXENV_STATUS_UNDI_INVALID_PARAMETER;
+ return PXENV_EXIT_FAILURE;
+ }
+ data = SEGOFF16_TO_PTR ( tbd->Xmit );
+ length = tbd->ImmedLength;
+
+ /* If destination is broadcast, we need to supply the MAC address */
+ if ( undi_transmit->XmitFlag == XMT_BROADCAST ) {
+ dest = broadcast_mac;
+ } else {
+ dest = SEGOFF16_TO_PTR ( undi_transmit->DestAddr );
+ }
+
+ /* We can't properly support P_UNKNOWN without rewriting all
+ * the driver transmit() methods, so we cheat: if P_UNKNOWN is
+ * specified we rip the destination address and type out of
+ * the pre-assembled packet, then skip over the header.
+ */
+ switch ( undi_transmit->Protocol ) {
+ case P_IP: type = IP; break;
+ case P_ARP: type = ARP; break;
+ case P_RARP: type = RARP; break;
+ case P_UNKNOWN:
+ media_header = (media_header_t*)data;
+ dest = media_header->dest;
+ type = ntohs ( media_header->nstype );
+ data += ETH_HLEN;
+ length -= ETH_HLEN;
+ break;
+ default:
+ undi_transmit->Status = PXENV_STATUS_UNDI_INVALID_PARAMETER;
+ return PXENV_EXIT_FAILURE;
+ }
+
+ /* Send the packet */
+ eth_transmit ( dest, type, length, data );
+
+ undi_transmit->Status = PXENV_STATUS_SUCCESS;
+ return PXENV_EXIT_SUCCESS;
+}
+
+/* PXENV_UNDI_SET_MCAST_ADDRESS
+ *
+ * Status: stub (no PXE multicast support)
+ */
+PXENV_EXIT_t
+pxenv_undi_set_mcast_address ( struct s_PXENV_UNDI_SET_MCAST_ADDRESS
+ *undi_set_mcast_address ) {
+ DBG ( "PXENV_UNDI_SET_MCAST_ADDRESS" );
+ /* ENSURE_READY ( undi_set_mcast_address ); */
+ undi_set_mcast_address->Status = PXENV_STATUS_UNSUPPORTED;
+ return PXENV_EXIT_FAILURE;
+}
+
+/* PXENV_UNDI_SET_STATION_ADDRESS
+ *
+ * Status: working (deliberately incomplete)
+ */
+PXENV_EXIT_t
+pxenv_undi_set_station_address ( struct s_PXENV_UNDI_SET_STATION_ADDRESS
+ *undi_set_station_address ) {
+ DBG ( "PXENV_UNDI_SET_STATION_ADDRESS" );
+ ENSURE_READY ( undi_set_station_address );
+
+ /* We don't offer a facility to set the MAC address; this
+ * would require adding extra code to all the Etherboot
+ * drivers, for very little benefit. If we're setting it to
+ * the current value anyway then return success, otherwise
+ * return UNSUPPORTED.
+ */
+ if ( memcmp ( nic.node_addr,
+ &undi_set_station_address->StationAddress,
+ ETH_ALEN ) == 0 ) {
+ undi_set_station_address->Status = PXENV_STATUS_SUCCESS;
+ return PXENV_EXIT_SUCCESS;
+ }
+ undi_set_station_address->Status = PXENV_STATUS_UNSUPPORTED;
+ return PXENV_EXIT_FAILURE;
+}
+
+/* PXENV_UNDI_SET_PACKET_FILTER
+ *
+ * Status: won't implement (would require driver API changes for no
+ * real benefit)
+ */
+PXENV_EXIT_t
+pxenv_undi_set_packet_filter ( struct s_PXENV_UNDI_SET_PACKET_FILTER
+ *undi_set_packet_filter ) {
+ DBG ( "PXENV_UNDI_SET_PACKET_FILTER" );
+ /* ENSURE_READY ( undi_set_packet_filter ); */
+ undi_set_packet_filter->Status = PXENV_STATUS_UNSUPPORTED;
+ return PXENV_EXIT_FAILURE;
+}
+
+/* PXENV_UNDI_GET_INFORMATION
+ *
+ * Status: working
+ */
+PXENV_EXIT_t pxenv_undi_get_information ( struct s_PXENV_UNDI_GET_INFORMATION
+ *undi_get_information ) {
+ DBG ( "PXENV_UNDI_GET_INFORMATION" );
+ ENSURE_READY ( undi_get_information );
+
+ undi_get_information->BaseIo = nic.ioaddr;
+ undi_get_information->IntNumber = nic.irqno;
+ /* Cheat: assume all cards can cope with this */
+ undi_get_information->MaxTranUnit = ETH_MAX_MTU;
+ /* Cheat: we only ever have Ethernet cards */
+ undi_get_information->HwType = ETHER_TYPE;
+ undi_get_information->HwAddrLen = ETH_ALEN;
+ /* Cheat: assume card is always configured with its permanent
+ * node address. This is a valid assumption within Etherboot
+ * at the time of writing.
+ */
+ memcpy ( &undi_get_information->CurrentNodeAddress, nic.node_addr,
+ ETH_ALEN );
+ memcpy ( &undi_get_information->PermNodeAddress, nic.node_addr,
+ ETH_ALEN );
+ undi_get_information->ROMAddress = 0;
+ /* nic.rom_info->rom_segment; */
+ /* We only provide the ability to receive or transmit a single
+ * packet at a time. This is a bootloader, not an OS.
+ */
+ undi_get_information->RxBufCt = 1;
+ undi_get_information->TxBufCt = 1;
+ undi_get_information->Status = PXENV_STATUS_SUCCESS;
+ return PXENV_EXIT_SUCCESS;
+}
+
+/* PXENV_UNDI_GET_STATISTICS
+ *
+ * Status: won't implement (would require driver API changes for no
+ * real benefit)
+ */
+PXENV_EXIT_t pxenv_undi_get_statistics ( struct s_PXENV_UNDI_GET_STATISTICS
+ *undi_get_statistics ) {
+ DBG ( "PXENV_UNDI_GET_STATISTICS" );
+ /* ENSURE_READY ( undi_get_statistics ); */
+ undi_get_statistics->Status = PXENV_STATUS_UNSUPPORTED;
+ return PXENV_EXIT_FAILURE;
+}
+
+/* PXENV_UNDI_CLEAR_STATISTICS
+ *
+ * Status: won't implement (would require driver API changes for no
+ * real benefit)
+ */
+PXENV_EXIT_t pxenv_undi_clear_statistics ( struct s_PXENV_UNDI_CLEAR_STATISTICS
+ *undi_clear_statistics ) {
+ DBG ( "PXENV_UNDI_CLEAR_STATISTICS" );
+ /* ENSURE_READY ( undi_clear_statistics ); */
+ undi_clear_statistics->Status = PXENV_STATUS_UNSUPPORTED;
+ return PXENV_EXIT_FAILURE;
+}
+
+/* PXENV_UNDI_INITIATE_DIAGS
+ *
+ * Status: won't implement (would require driver API changes for no
+ * real benefit)
+ */
+PXENV_EXIT_t pxenv_undi_initiate_diags ( struct s_PXENV_UNDI_INITIATE_DIAGS
+ *undi_initiate_diags ) {
+ DBG ( "PXENV_UNDI_INITIATE_DIAGS" );
+ /* ENSURE_READY ( undi_initiate_diags ); */
+ undi_initiate_diags->Status = PXENV_STATUS_UNSUPPORTED;
+ return PXENV_EXIT_FAILURE;
+}
+
+/* PXENV_UNDI_FORCE_INTERRUPT
+ *
+ * Status: working
+ */
+PXENV_EXIT_t pxenv_undi_force_interrupt ( struct s_PXENV_UNDI_FORCE_INTERRUPT
+ *undi_force_interrupt ) {
+ DBG ( "PXENV_UNDI_FORCE_INTERRUPT" );
+ ENSURE_READY ( undi_force_interrupt );
+
+ eth_irq ( FORCE );
+ undi_force_interrupt->Status = PXENV_STATUS_SUCCESS;
+ return PXENV_EXIT_SUCCESS;
+}
+
+/* PXENV_UNDI_GET_MCAST_ADDRESS
+ *
+ * Status: stub (no PXE multicast support)
+ */
+PXENV_EXIT_t
+pxenv_undi_get_mcast_address ( struct s_PXENV_UNDI_GET_MCAST_ADDRESS
+ *undi_get_mcast_address ) {
+ DBG ( "PXENV_UNDI_GET_MCAST_ADDRESS" );
+ /* ENSURE_READY ( undi_get_mcast_address ); */
+ undi_get_mcast_address->Status = PXENV_STATUS_UNSUPPORTED;
+ return PXENV_EXIT_FAILURE;
+}
+
+/* PXENV_UNDI_GET_NIC_TYPE
+ *
+ * Status: working
+ */
+PXENV_EXIT_t pxenv_undi_get_nic_type ( struct s_PXENV_UNDI_GET_NIC_TYPE
+ *undi_get_nic_type ) {
+#warning "device probing mechanism has changed completely"
+
+#if 0
+ struct dev *dev = &dev;
+
+ DBG ( "PXENV_UNDI_GET_NIC_TYPE" );
+ ENSURE_READY ( undi_get_nic_type );
+
+ if ( dev->to_probe == PROBE_PCI ) {
+ struct pci_device *pci = &dev->state.pci.dev;
+
+ undi_get_nic_type->NicType = PCI_NIC;
+ undi_get_nic_type->info.pci.Vendor_ID = pci->vendor;
+ undi_get_nic_type->info.pci.Dev_ID = pci->dev_id;
+ undi_get_nic_type->info.pci.Base_Class = pci->class >> 8;
+ undi_get_nic_type->info.pci.Sub_Class = pci->class & 0xff;
+ undi_get_nic_type->info.pci.BusDevFunc =
+ ( pci->bus << 8 ) | pci->devfn;
+ /* Cheat: these fields are probably unnecessary, and
+ * would require adding extra code to pci.c.
+ */
+ undi_get_nic_type->info.pci.Prog_Intf = 0;
+ undi_get_nic_type->info.pci.Rev = 0;
+ undi_get_nic_type->info.pci.SubVendor_ID = 0xffff;
+ undi_get_nic_type->info.pci.SubDevice_ID = 0xffff;
+ } else if ( dev->to_probe == PROBE_ISA ) {
+ /* const struct isa_driver *isa = dev->state.isa.driver; */
+
+ undi_get_nic_type->NicType = PnP_NIC;
+ /* Don't think anything fills these fields in, and
+ * probably no-one will ever be interested in them.
+ */
+ undi_get_nic_type->info.pnp.EISA_Dev_ID = 0;
+ undi_get_nic_type->info.pnp.Base_Class = 0;
+ undi_get_nic_type->info.pnp.Sub_Class = 0;
+ undi_get_nic_type->info.pnp.Prog_Intf = 0;
+ undi_get_nic_type->info.pnp.CardSelNum = 0;
+ } else {
+ /* PXESPEC: There doesn't seem to be an "unknown type"
+ * defined.
+ */
+ undi_get_nic_type->NicType = 0;
+ }
+ undi_get_nic_type->Status = PXENV_STATUS_SUCCESS;
+ return PXENV_EXIT_SUCCESS;
+
+#endif
+}
+
+/* PXENV_UNDI_GET_IFACE_INFO
+ *
+ * Status: working
+ */
+PXENV_EXIT_t pxenv_undi_get_iface_info ( struct s_PXENV_UNDI_GET_IFACE_INFO
+ *undi_get_iface_info ) {
+ DBG ( "PXENV_UNDI_GET_IFACE_INFO" );
+ ENSURE_READY ( undi_get_iface_info );
+
+ /* Just hand back some info, doesn't really matter what it is.
+ * Most PXE stacks seem to take this approach.
+ */
+ sprintf ( undi_get_iface_info->IfaceType, "Etherboot" );
+ undi_get_iface_info->LinkSpeed = 10000000; /* 10 Mbps */
+ undi_get_iface_info->ServiceFlags = 0;
+ memset ( undi_get_iface_info->Reserved, 0,
+ sizeof(undi_get_iface_info->Reserved) );
+ undi_get_iface_info->Status = PXENV_STATUS_SUCCESS;
+ return PXENV_EXIT_SUCCESS;
+}
+
+/* PXENV_UNDI_GET_STATE
+ *
+ * Status: impossible
+ */
+PXENV_EXIT_t pxenv_undi_get_state ( struct s_PXENV_UNDI_GET_STATE
+ *undi_get_state ) {
+ undi_get_state->Status = PXENV_STATUS_UNSUPPORTED;
+ return PXENV_EXIT_FAILURE;
+};
+
+/* PXENV_UNDI_ISR
+ *
+ * Status: working
+ */
+PXENV_EXIT_t pxenv_undi_isr ( struct s_PXENV_UNDI_ISR *undi_isr ) {
+ media_header_t *media_header = (media_header_t*)nic.packet;
+
+ DBG ( "PXENV_UNDI_ISR" );
+ /* We can't call ENSURE_READY, because this could be being
+ * called as part of an interrupt service routine. Instead,
+ * we should simply die if we're not READY.
+ */
+ if ( ( pxe_stack == NULL ) || ( pxe_stack->state < READY ) ) {
+ undi_isr->Status = PXENV_STATUS_UNDI_INVALID_STATE;
+ return PXENV_EXIT_FAILURE;
+ }
+
+ /* Just in case some idiot actually looks at these fields when
+ * we weren't meant to fill them in...
+ */
+ undi_isr->BufferLength = 0;
+ undi_isr->FrameLength = 0;
+ undi_isr->FrameHeaderLength = 0;
+ undi_isr->ProtType = 0;
+ undi_isr->PktType = 0;
+
+ switch ( undi_isr->FuncFlag ) {
+ case PXENV_UNDI_ISR_IN_START :
+ /* Is there a packet waiting? If so, disable
+ * interrupts on the NIC and return "it's ours". Do
+ * *not* necessarily acknowledge the interrupt; this
+ * can happen later when eth_poll(1) is called. As
+ * long as the interrupt is masked off so that it
+ * doesn't immediately retrigger the 8259A then all
+ * should be well.
+ */
+ DBG ( " START" );
+ if ( eth_poll ( 0 ) ) {
+ DBG ( " OURS" );
+ eth_irq ( DISABLE );
+ undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_OURS;
+ } else {
+ DBG ( " NOT_OURS" );
+ undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_NOT_OURS;
+ }
+ break;
+ case PXENV_UNDI_ISR_IN_PROCESS :
+ /* Call poll(), return packet. If no packet, return "done".
+ */
+ DBG ( " PROCESS" );
+ if ( eth_poll ( 1 ) ) {
+ DBG ( " RECEIVE %d", nic.packetlen );
+ if ( nic.packetlen > sizeof(pxe_stack->packet) ) {
+ /* Should never happen */
+ undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_DONE;
+ undi_isr->Status =
+ PXENV_STATUS_OUT_OF_RESOURCES;
+ return PXENV_EXIT_FAILURE;
+ }
+ undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_RECEIVE;
+ undi_isr->BufferLength = nic.packetlen;
+ undi_isr->FrameLength = nic.packetlen;
+ undi_isr->FrameHeaderLength = ETH_HLEN;
+ memcpy ( pxe_stack->packet, nic.packet, nic.packetlen);
+ PTR_TO_SEGOFF16 ( pxe_stack->packet, undi_isr->Frame );
+ switch ( ntohs(media_header->nstype) ) {
+ case IP : undi_isr->ProtType = P_IP; break;
+ case ARP : undi_isr->ProtType = P_ARP; break;
+ case RARP : undi_isr->ProtType = P_RARP; break;
+ default : undi_isr->ProtType = P_UNKNOWN;
+ }
+ if ( memcmp ( media_header->dest, broadcast_mac,
+ sizeof(broadcast_mac) ) ) {
+ undi_isr->PktType = XMT_BROADCAST;
+ } else {
+ undi_isr->PktType = XMT_DESTADDR;
+ }
+ break;
+ } else {
+ /* No break - fall through to IN_GET_NEXT */
+ }
+ case PXENV_UNDI_ISR_IN_GET_NEXT :
+ /* We only ever return one frame at a time */
+ DBG ( " GET_NEXT DONE" );
+ /* Re-enable interrupts */
+ eth_irq ( ENABLE );
+ /* Force an interrupt if there's a packet still
+ * waiting, since we only handle one packet per
+ * interrupt.
+ */
+ if ( eth_poll ( 0 ) ) {
+ DBG ( " (RETRIGGER)" );
+ eth_irq ( FORCE );
+ }
+ undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_DONE;
+ break;
+ default :
+ /* Should never happen */
+ undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_DONE;
+ undi_isr->Status = PXENV_STATUS_UNDI_INVALID_PARAMETER;
+ return PXENV_EXIT_FAILURE;
+ }
+
+ undi_isr->Status = PXENV_STATUS_SUCCESS;
+ return PXENV_EXIT_SUCCESS;
+}
diff --git a/src/proto/fsp.c b/src/proto/fsp.c
new file mode 100644
index 000000000..6aba93762
--- /dev/null
+++ b/src/proto/fsp.c
@@ -0,0 +1,245 @@
+ /*********************************************************************\
+ * Copyright (c) 2005 by Radim Kolar (hsn-sendmail.cz) *
+ * *
+ * You may copy or modify this file in any manner you wish, provided *
+ * that this notice is always included, and that you hold the author *
+ * harmless for any loss or damage resulting from the installation or *
+ * use of this software. *
+ * *
+ * This file provides support for FSP v2 protocol written from scratch *
+ * by Radim Kolar, FSP project leader. *
+ * *
+ * ABOUT FSP *
+ * FSP is a lightweight file transfer protocol and is being used for *
+ * booting, Internet firmware updates, embedded devices and in *
+ * wireless applications. FSP is very easy to implement; contact Radim *
+ * Kolar if you need hand optimized assembler FSP stacks for various *
+ * microcontrollers, CPUs or consultations. *
+ * http://fsp.sourceforge.net/ *
+ * *
+ * REVISION HISTORY *
+ * 1.0 2005-03-17 rkolar Initial coding *
+ * 1.1 2005-03-24 rkolar We really need to send CC_BYE to the server *
+ * at end of transfer, because next stage boot *
+ * loader is unable to contact FSP server *
+ * until session timeouts. *
+ * 1.2 2005-03-26 rkolar We need to query filesize in advance, *
+ * because NBI loader do not reads file until *
+ * eof is reached.
+ * REMARKS *
+ * there is no support for selecting port number of fsp server, maybe *
+ * we should parse fsp:// URLs in boot image filename. *
+ * this implementation has filename limit 255 chars. *
+ \*********************************************************************/
+
+#ifdef DOWNLOAD_PROTO_FSP
+#include "etherboot.h"
+#include "nic.h"
+
+#define FSP_PORT 21
+
+/* FSP commands */
+#define CC_GET_FILE 0x42
+#define CC_BYE 0x4A
+#define CC_ERR 0x40
+#define CC_STAT 0x4D
+
+/* etherboot limits */
+#define FSP_MAXFILENAME 255
+
+struct fsp_info {
+ in_addr server_ip;
+ uint16_t server_port;
+ uint16_t local_port;
+ const char *filename;
+ int (*fnc)(unsigned char *, unsigned int, unsigned int, int);
+};
+
+struct fsp_header {
+ uint8_t cmd;
+ uint8_t sum;
+ uint16_t key;
+ uint16_t seq;
+ uint16_t len;
+ uint32_t pos;
+} PACKED;
+
+#define FSP_MAXPAYLOAD (ETH_MAX_MTU - \
+ (sizeof(struct iphdr) + sizeof(struct udphdr) + sizeof(struct fsp_header)))
+
+static struct fsp_request {
+ struct iphdr ip;
+ struct udphdr udp;
+ struct fsp_header fsp;
+ unsigned char data[FSP_MAXFILENAME + 1 + 2];
+} request;
+
+struct fsp_reply {
+ struct iphdr ip;
+ struct udphdr udp;
+ struct fsp_header fsp;
+ unsigned char data[FSP_MAXPAYLOAD];
+} PACKED;
+
+
+static int await_fsp(int ival, void *ptr, unsigned short ptype __unused,
+ struct iphdr *ip, struct udphdr *udp)
+{
+ if(!udp)
+ return 0;
+ if (ip->dest.s_addr != arptable[ARP_CLIENT].ipaddr.s_addr)
+ return 0;
+ if (ntohs(udp->dest) != ival)
+ return 0;
+ if (ntohs(udp->len) < 12+sizeof(struct udphdr))
+ return 0;
+ return 1;
+}
+
+static int proto_fsp(struct fsp_info *info)
+{
+ uint32_t filepos;
+ uint32_t filelength=0;
+ int i,retry;
+ uint16_t reqlen;
+ struct fsp_reply *reply;
+ int block=1;
+
+ /* prepare FSP request packet */
+ filepos=0;
+ i=strlen(info->filename);
+ if(i>FSP_MAXFILENAME)
+ {
+ printf("Boot filename is too long.\n");
+ return 0;
+ }
+ strcpy(request.data,info->filename);
+ *(uint16_t *)(request.data+i+1)=htons(FSP_MAXPAYLOAD);
+ request.fsp.len=htons(i+1);
+ reqlen=i+3+12;
+
+ rx_qdrain();
+ retry=0;
+
+ /* main loop */
+ for(;;) {
+ int sum;
+ long timeout;
+
+ /* query filelength if not known */
+ if(filelength == 0)
+ request.fsp.cmd=CC_STAT;
+
+ /* prepare request packet */
+ request.fsp.pos=htonl(filepos);
+ request.fsp.seq=random();
+ request.fsp.sum=0;
+ for(i=0,sum=reqlen;i<reqlen;i++)
+ {
+ sum += ((uint8_t *)&request.fsp)[i];
+ }
+ request.fsp.sum= sum + (sum >> 8);
+ /* send request */
+ if (!udp_transmit(info->server_ip.s_addr, info->local_port,
+ info->server_port, sizeof(request.ip) +
+ sizeof(request.udp) + reqlen, &request))
+ return (0);
+ /* wait for retry */
+#ifdef CONGESTED
+ timeout =
+ rfc2131_sleep_interval(filepos ? TFTP_REXMT : TIMEOUT, retry);
+#else
+ timeout = rfc2131_sleep_interval(TIMEOUT, retry);
+#endif
+ retry++;
+ if (!await_reply(await_fsp, info->local_port, NULL, timeout))
+ continue;
+ reply=(struct fsp_reply *) &nic.packet[ETH_HLEN];
+ /* check received packet */
+ if (reply->fsp.seq != request.fsp.seq)
+ continue;
+ reply->udp.len=ntohs(reply->udp.len)-sizeof(struct udphdr);
+ if(reply->udp.len < ntohs(reply->fsp.len) + 12 )
+ continue;
+ sum=-reply->fsp.sum;
+ for(i=0;i<reply->udp.len;i++)
+ {
+ sum += ((uint8_t *)&(reply->fsp))[i];
+ }
+ sum = (sum + (sum >> 8)) & 0xff;
+ if(sum != reply->fsp.sum)
+ {
+ printf("FSP checksum failed. computed %d, but packet has %d.\n",sum,reply->fsp.sum);
+ continue;
+ }
+ if(reply->fsp.cmd == CC_ERR)
+ {
+ printf("\nFSP error: %s",info->filename);
+ if(reply->fsp.len)
+ printf(" [%s]",reply->data);
+ printf("\n");
+ return 0;
+ }
+ if(reply->fsp.cmd == CC_BYE && filelength == 1)
+ {
+ info->fnc(request.data,block,1,1);
+ return 1;
+ }
+ if(reply->fsp.cmd == CC_STAT)
+ {
+ if(reply->data[8] == 0)
+ {
+ /* file not found, etc. */
+ filelength=0xffffffff;
+ } else
+ {
+ filelength= ntohl(*((uint32_t *)&reply->data[4]));
+ }
+ request.fsp.cmd = CC_GET_FILE;
+ request.fsp.key = reply->fsp.key;
+ retry=0;
+ continue;
+ }
+
+ if(reply->fsp.cmd == CC_GET_FILE)
+ {
+ if(ntohl(reply->fsp.pos) != filepos)
+ continue;
+ request.fsp.key = reply->fsp.key;
+ retry=0;
+ i=ntohs(reply->fsp.len);
+ if(i == 1)
+ {
+ request.fsp.cmd=CC_BYE;
+ request.data[0]=reply->data[0];
+ continue;
+ }
+ /* let last byte alone */
+ if(i >= filelength)
+ i = filelength - 1;
+ if(!info->fnc(reply->data,block++,i,0))
+ return 0;
+ filepos += i;
+ filelength -= i;
+ }
+ }
+
+ return 0;
+}
+
+int url_fsp(const char *name, int (*fnc)(unsigned char *, unsigned int, unsigned int, int))
+{
+ struct fsp_info info;
+ /* Set the defaults */
+ info.server_ip.s_addr = arptable[ARP_SERVER].ipaddr.s_addr;
+ info.server_port = FSP_PORT;
+ info.local_port = 1024 + random() & 0xfbff;
+ info.fnc = fnc;
+
+ /* Now parse the url */
+ /* printf("fsp-URI: [%s]\n", name); */
+ /* quick hack for now */
+ info.filename=name;
+ return proto_fsp(&info);
+}
+#endif
diff --git a/src/proto/http.c b/src/proto/http.c
index 6f47fc14d..4fa594f66 100644
--- a/src/proto/http.c
+++ b/src/proto/http.c
@@ -40,18 +40,19 @@ static int send_tcp_request(int length, void *buffer, void *ptr) {
/**************************************************************************
RECV_TCP_CALLBACK - Receive data using TCP
**************************************************************************/
-static int recv_tcp_request(int length, const void *buffer, void *ptr) {
+static int recv_tcp_request(int length, const void *data, void *ptr) {
struct send_recv_state *state = (struct send_recv_state *)ptr;
+ const char *buffer = data;
/* Assume that the lines in an HTTP header do not straddle a packet */
/* boundary. This is probably a reasonable assumption */
if (state->recv_state == RESULT_CODE) {
while (length > 0) {
/* Find HTTP result code */
- if (*(const char *)buffer == ' ') {
- const char *ptr = ((const char *)buffer) + 1;
+ if (*buffer == ' ') {
+ const char *ptr = buffer + 1;
int rc = strtoul(ptr, &ptr, 10);
- if (ptr >= (const char *)buffer + length) {
+ if (ptr >= buffer + length) {
state->recv_state = ERROR;
DBG ( "HTTP got bad result code\n" );
return 0;
@@ -61,7 +62,7 @@ static int recv_tcp_request(int length, const void *buffer, void *ptr) {
DBG ( "HTTP got result code %d\n", rc );
goto header;
}
- ++(const char *)buffer;
+ ++buffer;
length--;
}
state->recv_state = ERROR;
@@ -88,7 +89,7 @@ static int recv_tcp_request(int length, const void *buffer, void *ptr) {
/* Find beginning of line */
while (length > 0) {
length--;
- if (*((const char *)buffer)++ == '\n')
+ if (*buffer++ == '\n')
break;
}
/* Check for end of header */
@@ -140,7 +141,7 @@ static int http ( char *url, struct sockaddr_in *server __unused,
tcp_transaction ( server->sin_addr.s_addr,
server->sin_port, &state,
- send_tcp_request, recv_tcp_request );
+ send_tcp_request, (int (*)(int, const void *, void *))recv_tcp_request );
}
if ( state.recv_state == MOVED ) {
diff --git a/src/proto/igmp.c b/src/proto/igmp.c
new file mode 100644
index 000000000..aad530f74
--- /dev/null
+++ b/src/proto/igmp.c
@@ -0,0 +1,166 @@
+/*
+ * Eric Biederman wrote this code originally.
+ *
+ */
+
+#include "ip.h"
+#include "igmp.h"
+#include "background.h"
+#include "nic.h"
+#include "etherboot.h"
+
+static unsigned long last_igmpv1 = 0;
+static struct igmptable_t igmptable[MAX_IGMP];
+
+static long rfc1112_sleep_interval ( long base, int exp ) {
+ unsigned long divisor, tmo;
+
+ if ( exp > BACKOFF_LIMIT )
+ exp = BACKOFF_LIMIT;
+ divisor = RAND_MAX / ( base << exp );
+ tmo = random() / divisor;
+ return tmo;
+}
+
+static void send_igmp_reports ( unsigned long now ) {
+ struct igmp_ip_t igmp;
+ int i;
+
+ for ( i = 0 ; i < MAX_IGMP ; i++ ) {
+ if ( ! igmptable[i].time )
+ continue;
+ if ( now < igmptable[i].time )
+ continue;
+
+ igmp.router_alert[0] = 0x94;
+ igmp.router_alert[1] = 0x04;
+ igmp.router_alert[2] = 0;
+ igmp.router_alert[3] = 0;
+ build_ip_hdr ( igmptable[i].group.s_addr, 1, IP_IGMP,
+ sizeof ( igmp.router_alert ),
+ sizeof ( igmp ), &igmp );
+ igmp.igmp.type = IGMPv2_REPORT;
+ if ( last_igmpv1 &&
+ ( now < last_igmpv1 + IGMPv1_ROUTER_PRESENT_TIMEOUT ) ) {
+ igmp.igmp.type = IGMPv1_REPORT;
+ }
+ igmp.igmp.response_time = 0;
+ igmp.igmp.chksum = 0;
+ igmp.igmp.group.s_addr = igmptable[i].group.s_addr;
+ igmp.igmp.chksum = ipchksum ( &igmp.igmp,
+ sizeof ( igmp.igmp ) );
+ ip_transmit ( sizeof ( igmp ), &igmp );
+ DBG ( "IGMP sent report to %@\n",
+ igmp.igmp.group.s_addr );
+ /* Don't send another igmp report until asked */
+ igmptable[i].time = 0;
+ }
+}
+
+static void process_igmp ( unsigned long now, unsigned short ptype __unused,
+ struct iphdr *ip ) {
+ struct igmp *igmp;
+ int i;
+ unsigned iplen;
+
+ if ( ( ! ip ) || ( ip->protocol != IP_IGMP ) ||
+ ( nic.packetlen < ( sizeof ( struct iphdr ) +
+ sizeof ( struct igmp ) ) ) ) {
+ return;
+ }
+
+ iplen = ( ip->verhdrlen & 0xf ) * 4;
+ igmp = ( struct igmp * ) &nic.packet[ sizeof( struct iphdr ) ];
+ if ( ipchksum ( igmp, ntohs ( ip->len ) - iplen ) != 0 )
+ return;
+
+ if ( ( igmp->type == IGMP_QUERY ) &&
+ ( ip->dest.s_addr == htonl ( GROUP_ALL_HOSTS ) ) ) {
+ unsigned long interval = IGMP_INTERVAL;
+
+ if ( igmp->response_time == 0 ) {
+ last_igmpv1 = now;
+ } else {
+ interval = ( igmp->response_time * TICKS_PER_SEC ) /10;
+ }
+
+ DBG ( "IGMP received query for %@\n", igmp->group.s_addr );
+ for ( i = 0 ; i < MAX_IGMP ; i++ ) {
+ uint32_t group = igmptable[i].group.s_addr;
+ if ( ( group == 0 ) ||
+ ( group == igmp->group.s_addr ) ) {
+ unsigned long time;
+ time = currticks() +
+ rfc1112_sleep_interval ( interval, 0 );
+ if ( time < igmptable[i].time ) {
+ igmptable[i].time = time;
+ }
+ }
+ }
+ }
+ if ( ( ( igmp->type == IGMPv1_REPORT ) ||
+ ( igmp->type == IGMPv2_REPORT ) ) &&
+ ( ip->dest.s_addr == igmp->group.s_addr ) ) {
+ DBG ( "IGMP received report for %@\n", igmp->group.s_addr);
+ for ( i = 0 ; i < MAX_IGMP ; i++ ) {
+ if ( ( igmptable[i].group.s_addr ==
+ igmp->group.s_addr ) &&
+ ( igmptable[i].time != 0 ) ) {
+ igmptable[i].time = 0;
+ }
+ }
+ }
+}
+
+static struct background igmp_background __background = {
+ .send = send_igmp_reports,
+ .process = process_igmp,
+};
+
+void leave_group ( int slot ) {
+ /* Be very stupid and always send a leave group message if
+ * I have subscribed. Imperfect but it is standards
+ * compliant, easy and reliable to implement.
+ *
+ * The optimal group leave method is to only send leave when,
+ * we were the last host to respond to a query on this group,
+ * and igmpv1 compatibility is not enabled.
+ */
+ if ( igmptable[slot].group.s_addr ) {
+ struct igmp_ip_t igmp;
+
+ igmp.router_alert[0] = 0x94;
+ igmp.router_alert[1] = 0x04;
+ igmp.router_alert[2] = 0;
+ igmp.router_alert[3] = 0;
+ build_ip_hdr ( htonl ( GROUP_ALL_HOSTS ), 1, IP_IGMP,
+ sizeof ( igmp.router_alert ), sizeof ( igmp ),
+ &igmp);
+ igmp.igmp.type = IGMP_LEAVE;
+ igmp.igmp.response_time = 0;
+ igmp.igmp.chksum = 0;
+ igmp.igmp.group.s_addr = igmptable[slot].group.s_addr;
+ igmp.igmp.chksum = ipchksum ( &igmp.igmp, sizeof ( igmp ) );
+ ip_transmit ( sizeof ( igmp ), &igmp );
+ DBG ( "IGMP left group %@\n", igmp.igmp.group.s_addr );
+ }
+ memset ( &igmptable[slot], 0, sizeof ( igmptable[0] ) );
+}
+
+void join_group ( int slot, unsigned long group ) {
+ /* I have already joined */
+ if ( igmptable[slot].group.s_addr == group )
+ return;
+ if ( igmptable[slot].group.s_addr ) {
+ leave_group ( slot );
+ }
+ /* Only join a group if we are given a multicast ip, this way
+ * code can be given a non-multicast (broadcast or unicast ip)
+ * and still work...
+ */
+ if ( ( group & htonl ( MULTICAST_MASK ) ) ==
+ htonl ( MULTICAST_NETWORK ) ) {
+ igmptable[slot].group.s_addr = group;
+ igmptable[slot].time = currticks();
+ }
+}
diff --git a/src/proto/nfs.c b/src/proto/nfs.c
index 2d8378975..311409a6b 100644
--- a/src/proto/nfs.c
+++ b/src/proto/nfs.c
@@ -575,7 +575,7 @@ nfssymlink:
return 0;
}
if (err) {
- printf("reading at offset %d: ", offs);
+ printf("\nError reading at offset %d: ", offs);
nfs_printerror(err);
nfs_reset();
return 0;
diff --git a/src/proto/nmb.c b/src/proto/nmb.c
index b395dabeb..d44c06850 100644
--- a/src/proto/nmb.c
+++ b/src/proto/nmb.c
@@ -15,6 +15,7 @@ static inline char * nbns_make_name ( char *dest, const char *name ) {
char nb_name[16];
char c;
int i;
+ uint16_t *d;
*(dest++) = 32; /* Length is always 32 */
@@ -26,11 +27,13 @@ static inline char * nbns_make_name ( char *dest, const char *name ) {
memset ( nb_name, ' ', 15 );
nb_name[15] = '\0';
memcpy ( nb_name, name, strlen ( name ) ); /* Do not copy NUL */
+
+ d = ( uint16_t * ) dest;
for ( i = 0 ; i < 16 ; i++ ) {
c = nb_name[i];
- *( ( ( uint16_t * ) dest ) ++ ) =
- htons ( ( ( c | ( c << 4 ) ) & 0x0f0f ) + 0x4141 );
+ *( d++ ) = htons ( ( ( c | ( c << 4 ) ) & 0x0f0f ) + 0x4141 );
}
+ dest = ( char * ) d;
*(dest++) = 0; /* Terminating 0-length name component */
return dest;
diff --git a/src/proto/tcp.c b/src/proto/tcp.c
index 197bfce2e..1e0531d5c 100644
--- a/src/proto/tcp.c
+++ b/src/proto/tcp.c
@@ -1,7 +1,7 @@
#include "etherboot.h"
#include "ip.h"
#include "tcp.h"
-
+#include "nic.h"
void build_tcp_hdr(unsigned long destip, unsigned int srcsock,
unsigned int destsock, long send_seq, long recv_seq,
diff --git a/src/proto/tftm.c b/src/proto/tftm.c
index 426d0dda8..fb011c624 100644
--- a/src/proto/tftm.c
+++ b/src/proto/tftm.c
@@ -1,483 +1,208 @@
-/**************************************************************************
-*
-* proto_tftm.c -- Etherboot Multicast TFTP
-* Written 2003-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.
-*
-* This code is based on the DOWNLOAD_PROTO_TFTM section of
-* Etherboot 5.3 core/nic.c and:
-*
-* Anselm Martin Hoffmeister's previous proto_tftm.c multicast work
-* Eric Biederman's proto_slam.c
-*
-* $Revision$
-* $Author$
-* $Date$
-*
-* REVISION HISTORY:
-* ================
-* 09-07-2003 timlegge Release Version, Capable of Multicast Booting
-* 08-30-2003 timlegge Initial version, Assumes consecutive blocks
-*
-* Indent Options: indent -kr -i8
-***************************************************************************/
+#include "etherboot.h"
+#include "proto.h"
+#include "errno.h"
+#include "tftp.h"
+#include "tftpcore.h"
-/*
- * IMPORTANT
+/** @file
*
- * This file should be rewritten to avoid the use of a bitmap. Our
- * buffer routines can cope with being handed blocks in an arbitrary
- * order, duplicate blocks, etc. This code could be substantially
- * simplified by taking advantage of these features.
+ * TFTM protocol
*
+ * TFTM is a protocol defined in RFC2090 as a multicast extension to
+ * TFTP.
*/
-#include "etherboot.h"
-#include "proto.h"
-#include "nic.h"
+static inline int tftm_process_opts ( struct tftp_state *state,
+ struct tftp_oack *oack ) {
+ struct in_addr old_mcast_addr = state->multicast.sin_addr;
-struct tftm_info {
- struct sockaddr_in server;
- struct sockaddr_in local;
- struct sockaddr_in multicast;
- int sent_nack;
- const char *name; /* Filename */
-};
+ if ( ! tftp_process_opts ( state, oack ) )
+ return 0;
-struct tftm_state {
- unsigned long block_size;
- unsigned long total_bytes;
- unsigned long total_packets;
- char ismaster;
- unsigned long received_packets;
- struct buffer *buffer;
- unsigned char *image;
- unsigned char *bitmap;
- char recvd_oack;
-} state;
+ if ( old_mcast_addr.s_addr != state->multicast.sin_addr.s_addr ) {
+ if ( old_mcast_addr.s_addr ) {
+ DBG ( "TFTM: Leaving multicast group %@\n",
+ old_mcast_addr.s_addr );
+ leave_group ( IGMP_SERVER );
+ }
+ DBG ( "TFTM: Joining multicast group %@\n",
+ state->multicast.sin_addr.s_addr );
+ join_group ( IGMP_SERVER, state->multicast.sin_addr.s_addr );
+ }
-#define TFTM_PORT 1758
-#define TFTM_MIN_PACKET 1024
+ DBG ( "TFTM: I am a %s client\n",
+ ( state->master ? "master" : "slave" ) );
+ return 1;
+}
-static int opt_get_multicast(struct tftp_t *tr, unsigned short *len,
- unsigned long *filesize, struct tftm_info *info);
-static int await_tftm(int ival, void *ptr, unsigned short ptype __unused,
- struct iphdr *ip, struct udphdr *udp,
- struct tcphdr *tcp __unused)
-{
- struct tftm_info *info = ptr;
+static inline int tftm_process_data ( struct tftp_state *state,
+ struct tftp_data *data,
+ struct buffer *buffer ) {
+ unsigned int blksize;
+ off_t offset;
- /* Check for Unicast data being received */
- if (ip->dest.s_addr == arptable[ARP_CLIENT].ipaddr.s_addr) {
- if (!udp) {
- return 0;
- }
- if (arptable[ARP_CLIENT].ipaddr.s_addr != ip->dest.s_addr)
- return 0;
- if (ntohs(udp->dest) != ival)
- return 0;
+ /* Calculate block size and offset within file */
+ blksize = ( ntohs ( data->udp.len )
+ + offsetof ( typeof ( *data ), udp )
+ - offsetof ( typeof ( *data ), data ) );
+ offset = ( ntohs ( data->block ) - 1 ) * state->blksize;
- return 1; /* Unicast Data Received */
+ /* Check for oversized block */
+ if ( blksize > state->blksize ) {
+ DBG ( "TFTM: oversized block size %d (max %d)\n",
+ blksize, state->blksize );
+ errno = PXENV_STATUS_TFTP_INVALID_PACKET_SIZE;
+ return 0;
}
- /* Also check for Multicast data being received */
- if ((ip->dest.s_addr == info->multicast.sin_addr.s_addr) &&
- (ntohs(udp->dest) == info->multicast.sin_port) &&
- (nic.packetlen >= ETH_HLEN + sizeof(struct iphdr) +
- sizeof(struct udphdr))) {
- return 1; /* Multicast data received */
+ /* Place block in the buffer */
+ if ( ! fill_buffer ( buffer, data->data, offset, blksize ) ) {
+ DBG ( "TFTM: could not place data in buffer: %m\n" );
+ return 0;
}
- return 0;
-}
-static int proto_tftm(struct tftm_info *info)
-{
- int retry = 0;
- static unsigned short iport = 2000;
- unsigned short oport = 0;
- unsigned short len, block = 0, prevblock = 0;
- struct tftp_t *tr;
- struct tftpreq_t tp;
- unsigned long filesize = 0;
+ /* If this is the last block, record the filesize (in case the
+ * server didn't supply a tsize option.
+ */
+ if ( blksize < state->blksize ) {
+ state->tsize = offset + blksize;
+ }
- state.image = 0;
- state.bitmap = 0;
+ /* Record the last received block */
+ state->block = ntohs ( data->block );
- rx_qdrain();
+ return 1;
+}
- /* Warning: the following assumes the layout of bootp_t.
- But that's fixed by the IP, UDP and BOOTP specs. */
- /* Send a tftm-request to the server */
- tp.opcode = htons(TFTP_RRQ); /* Const for "\0x0" "\0x1" =^= ReadReQuest */
- len =
- sizeof(tp.ip) + sizeof(tp.udp) + sizeof(tp.opcode) +
- sprintf((char *) tp.u.rrq,
- "%s%coctet%cmulticast%c%cblksize%c%d%ctsize%c",
- info->name, 0, 0, 0, 0, 0, TFTM_MIN_PACKET, 0, 0) + 1;
+static inline int tftm_next ( struct tftp_state *state,
+ union tftp_any **reply,
+ struct buffer *buffer ) {
+ long listen_timeout;
- if (!udp_transmit(info->server.sin_addr.s_addr, ++iport,
- info->server.sin_port, len, &tp))
- return (0);
+ listen_timeout = rfc2131_sleep_interval ( TIMEOUT, MAX_TFTP_RETRIES );
- /* loop to listen for packets and to receive the file */
- for (;;) {
- long timeout;
-#ifdef CONGESTED
- timeout =
- rfc2131_sleep_interval(block ? TFTP_REXMT : TIMEOUT,
- retry);
-#else
- timeout = rfc2131_sleep_interval(TIMEOUT, retry);
-#endif
- /* Calls the await_reply function in nic.c which in turn calls
- await_tftm (1st parameter) as above */
- if (!await_reply(await_tftm, iport, info, timeout)) {
- if (!block && retry++ < MAX_TFTP_RETRIES) { /* maybe initial request was lost */
- if (!udp_transmit
- (info->server.sin_addr.s_addr, ++iport,
- info->server.sin_port, len, &tp))
- return (0);
- continue;
- }
-#ifdef CONGESTED
- if (block && ((retry += TFTP_REXMT) < TFTP_TIMEOUT)) { /* we resend our last ack */
- DBG("Timed out receiving file");
- len =
- sizeof(tp.ip) + sizeof(tp.udp) +
- sizeof(tp.opcode) +
- sprintf((char *) tp.u.rrq,
- "%s%coctet%cmulticast%c%cblksize%c%d%ctsize%c",
- info->name, 0, 0, 0, 0, 0,
- TFTM_MIN_PACKET, 0, 0) + 1;
-
- udp_transmit
- (info->server.sin_addr.s_addr,
- ++iport, info->server.sin_port,
- len, &tp);
- continue;
- }
-#endif
- break; /* timeout */
+ /* If we are not the master client, just listen for the next
+ * packet
+ */
+ if ( ! state->master ) {
+ if ( tftp_get ( state, listen_timeout, reply ) ) {
+ /* Heard a non-error packet */
+ return 1;
}
-
- tr = (struct tftp_t *) &nic.packet[ETH_HLEN];
-
- if (tr->opcode == ntohs(TFTP_ERROR)) {
- printf("TFTP error %d (%s)\n",
- ntohs(tr->u.err.errcode), tr->u.err.errmsg);
- break;
+ if ( *reply ) {
+ /* Received an error packet */
+ return 0;
}
+ /* Didn't hear anything; try prodding the server */
+ state->master = 1;
+ }
+ /* We are the master client; trigger the next packet
+ * that we want
+ */
+ state->block = buffer->fill / state->blksize;
+ return tftp_ack ( state, reply );
+}
- if (tr->opcode == ntohs(TFTP_OACK)) {
- int i =
- opt_get_multicast(tr, &len, &filesize, info);
-
- if (i == 0 || (i != 7 && !state.recvd_oack)) { /* Multicast unsupported */
- /* Transmit an error message to the server to end the transmission */
- printf
- ("TFTM-Server doesn't understand options [blksize tsize multicast]\n");
- tp.opcode = htons(TFTP_ERROR);
- tp.u.err.errcode = 8;
- /*
- * Warning: the following assumes the layout of bootp_t.
- * But that's fixed by the IP, UDP and BOOTP specs.
- */
- len =
- sizeof(tp.ip) + sizeof(tp.udp) +
- sizeof(tp.opcode) +
- sizeof(tp.u.err.errcode) +
- /*
- * Normally bad form to omit the format string, but in this case
- * the string we are copying from is fixed. sprintf is just being
- * used as a strcpy and strlen.
- */
- sprintf((char *) tp.u.err.errmsg,
- "RFC2090 error") + 1;
- udp_transmit(info->server.sin_addr.s_addr,
- iport, ntohs(tr->udp.src),
- len, &tp);
- block = tp.u.ack.block = 0; /* this ensures, that */
- /* the packet does not get */
- /* processed as data! */
- return (0);
- } else {
- unsigned long bitmap_len;
- /* */
- if (!state.recvd_oack) {
-
- state.total_packets =
- 1 + (filesize -
- (filesize %
- state.block_size)) /
- state.block_size;
- bitmap_len =
- (state.total_packets + 7) / 8;
- if (!state.image) {
- state.image = phys_to_virt ( state.buffer->start );
- state.bitmap = state.image + filesize;
- /* We don't yet use the buffer routines; fake it */
- state.buffer->fill = filesize;
-
- memset(state.bitmap, 0,
- bitmap_len);
- }
- /* If I'm running over multicast join the multicast group */
- join_group(IGMP_SERVER,
- info->multicast.sin_addr.s_addr);
- }
- state.recvd_oack = 1;
- }
-
-
-
- } else if (tr->opcode == htons(TFTP_DATA)) {
- unsigned long data_len;
- unsigned char *data;
- struct udphdr *udp;
- udp =
- (struct udphdr *) &nic.packet[ETH_HLEN +
- sizeof(struct
- iphdr)];
- len =
- ntohs(tr->udp.len) - sizeof(struct udphdr) - 4;
- data =
- nic.packet + ETH_HLEN + sizeof(struct iphdr) +
- sizeof(struct udphdr) + 4;
-
- if (len > TFTM_MIN_PACKET) /* shouldn't happen */
- continue; /* ignore it */
-
- block = ntohs(tp.u.ack.block = tr->u.data.block);
-
- if (block > state.total_packets) {
- printf("ALERT: Invalid packet number\n");
- continue;
- }
-
- /* Compute the expected data length */
- if (block != state.total_packets) {
- data_len = state.block_size;
- } else {
- data_len = filesize % state.block_size;
- }
- /* If the packet size is wrong drop the packet and then continue */
- if (ntohs(udp->len) !=
- (data_len + (data - (unsigned char *) udp))) {
- printf
- ("ALERT: udp packet is not the correct size: %d\n",
- block);
- continue;
- }
- if (nic.packetlen < data_len + (data - nic.packet)) {
- printf
- ("ALERT: Ethernet packet shorter than data_len: %d\n",
- block);
- continue;
- }
-
- if (data_len > state.block_size) {
- data_len = state.block_size;
- }
- if (((state.
- bitmap[block >> 3] >> (block & 7)) & 1) ==
- 0) {
- /* Non duplicate packet */
- state.bitmap[block >> 3] |=
- (1 << (block & 7));
- memcpy(state.image +
- ((block - 1) * state.block_size),
- data, data_len);
- state.received_packets++;
- } else {
+/**
+ * Download a file via TFTM
+ *
+ * @v server TFTP server
+ * @v file File name
+ * @v buffer Buffer into which to load file
+ * @ret True File was downloaded successfully
+ * @ret False File was not downloaded successfully
+ * @err #PXENV_STATUS_TFTP_UNKNOWN_OPCODE Unknown type of TFTP block received
+ * @err other As returned by tftp_open()
+ * @err other As returned by tftp_process_opts()
+ * @err other As returned by tftp_ack()
+ * @err other As returned by tftp_process_data()
+ *
+ * Download a file from a TFTP server into the specified buffer using
+ * the TFTM protocol.
+ */
+static int tftm ( char *url __unused, struct sockaddr_in *server, char *file,
+ struct buffer *buffer ) {
+ struct tftp_state state;
+ union tftp_any *reply;
+ int rc = 0;
+
+ /* Initialise TFTP state */
+ memset ( &state, 0, sizeof ( state ) );
+ state.server = *server;
+
+ /* Start as the master. This means that if the TFTP server
+ * doesn't actually support multicast, we'll still ACK the
+ * packets and it should all proceed as for a normal TFTP
+ * connection.
+ */
+ state.master = 1;
+
+ /* Open the file */
+ if ( ! tftp_open ( &state, file, &reply, 1 ) ) {
+ DBG ( "TFTM: could not open %@:%d/%s : %m\n",
+ server->sin_addr.s_addr, server->sin_port, file );
+ return 0;
+ }
-/* printf("<DUP>\n"); */
+ /* Fetch file, a block at a time */
+ while ( 1 ) {
+ twiddle();
+ /* Process the current packet */
+ switch ( ntohs ( reply->common.opcode ) ) {
+ case TFTP_OACK:
+ /* Options can be received at any time */
+ if ( ! tftm_process_opts ( &state, &reply->oack ) ) {
+ DBG ( "TFTM: failed to process OACK: %m\n" );
+ tftp_error ( &state, TFTP_ERR_BAD_OPTS, NULL );
+ goto out;
}
- }
-
- else { /* neither TFTP_OACK, TFTP_DATA nor TFTP_ERROR */
break;
- }
-
- if (state.received_packets <= state.total_packets) {
- unsigned long b;
- unsigned long len;
- unsigned long max;
- int value;
- int last;
-
- /* Compute the last bit and store an inverted trailer */
- max = state.total_packets + 1;
- value =
- ((state.
- bitmap[(max - 1) >> 3] >> ((max -
- 1) & 7)) & 1);
- value = !value;
- state.bitmap[max >> 3] &= ~(1 << (max & 7));
- state.bitmap[max >> 3] |= value << (max & 7);
-
- len = 0;
- last = 0; /* Start with the received packets */
- for (b = 1; b <= max; b++) {
- value =
- (state.bitmap[b >> 3] >> (b & 7)) & 1;
-
- if (value == 0) {
- tp.u.ack.block = htons(b - 1); /* Acknowledge the previous block */
- break;
- }
- }
- }
- if (state.ismaster) {
- tp.opcode = htons(TFTP_ACK);
- oport = ntohs(tr->udp.src);
- udp_transmit(info->server.sin_addr.s_addr, iport,
- oport, TFTP_MIN_PACKET, &tp); /* ack */
- }
- if (state.received_packets == state.total_packets) {
- /* If the client is finished and not the master,
- * ack the last packet */
- if (!state.ismaster) {
- tp.opcode = htons(TFTP_ACK);
- /* Ack Last packet to end xfer */
- tp.u.ack.block = htons(state.total_packets);
- oport = ntohs(tr->udp.src);
- udp_transmit(info->server.sin_addr.s_addr,
- iport, oport,
- TFTP_MIN_PACKET, &tp); /* ack */
+ case TFTP_DATA:
+ if ( ! tftm_process_data ( &state, &reply->data,
+ buffer ) ) {
+ DBG ( "TFTM: failed to process DATA: %m\n" );
+ tftp_error ( &state, TFTP_ERR_ILLEGAL_OP,
+ NULL );
+ goto out;
}
- /* We are done get out */
break;
+ default:
+ DBG ( "TFTM: unexpected packet type %d\n",
+ ntohs ( reply->common.opcode ) );
+ errno = PXENV_STATUS_TFTP_UNKNOWN_OPCODE;
+ tftp_error ( &state, TFTP_ERR_ILLEGAL_OP, NULL );
+ goto out;
}
-
- if ((unsigned short) (block - prevblock) != 1) {
- /* Retransmission or OACK, don't process via callback
- * and don't change the value of prevblock. */
- continue;
+ /* If we know the filesize, and we have all the data, stop */
+ if ( state.tsize && ( buffer->fill == state.tsize ) )
+ break;
+ /* Fetch the next packet */
+ if ( ! tftm_next ( &state, &reply, buffer ) ) {
+ DBG ( "TFTM: could not get next block: %m\n" );
+ if ( ! reply ) {
+ tftp_error ( &state, TFTP_ERR_ILLEGAL_OP,
+ NULL );
+ }
+ goto out;
}
-
- prevblock = block;
- retry = 0; /* It's the right place to zero the timer? */
-
- }
- /* Leave the multicast group */
- leave_group(IGMP_SERVER);
- return 1;
-}
-
-static int url_tftm ( char *url __unused, struct sockaddr_in *server,
- char *file, struct buffer *buffer ) {
-
- int ret;
- struct tftm_info info;
-
- /* Set the defaults */
- info.server = *server;
- info.local.sin_addr.s_addr = arptable[ARP_CLIENT].ipaddr.s_addr;
- info.local.sin_port = TFTM_PORT; /* Does not matter. */
- info.multicast = info.local;
- state.ismaster = 0;
- info.name = file;
-
- state.block_size = 0;
- state.total_bytes = 0;
- state.total_packets = 0;
- state.received_packets = 0;
- state.buffer = buffer;
- state.image = 0;
- state.bitmap = 0;
- state.recvd_oack = 0;
-
- if (file[0] != '/') {
- printf("Bad tftm-URI: [%s]\n", file);
- return 0;
}
- ret = proto_tftm(&info);
-
- return ret;
-}
-
-/******************************
-* Parse the multicast options
-*******************************/
-static int opt_get_multicast(struct tftp_t *tr, unsigned short *len,
- unsigned long *filesize, struct tftm_info *info)
-{
- const char *p = tr->u.oack.data, *e = 0;
- int i = 0;
- *len = ntohs(tr->udp.len) - sizeof(struct udphdr) - 2;
- if (*len > TFTM_MIN_PACKET)
- return -1;
- e = p + *len;
+ /* ACK the final packet, as a courtesy to the server */
+ tftp_ack_nowait ( &state );
- while (*p != '\0' && p < e) {
- if (!strcasecmp("tsize", p)) {
- p += 6;
- if ((*filesize = strtoul(p, &p, 10)) > 0)
- i |= 4;
- DBG("\n");
- DBG("tsize=%d\n", *filesize);
- while (p < e && *p)
- p++;
- if (p < e)
- p++;
- } else if (!strcasecmp("blksize", p)) {
- i |= 2;
- p += 8;
- state.block_size = strtoul(p, &p, 10);
- if (state.block_size != TFTM_MIN_PACKET) {
- printf
- ("TFTM-Server rejected required transfer blocksize %d\n",
- TFTM_MIN_PACKET);
- return 0;
- }
- DBG("blksize=%d\n", state.block_size);
- while (p < e && *p)
- p++;
- if (p < e)
- p++;
- } else if (!strncmp(p, "multicast", 10)) {
- i |= 1;
- p += 10;
- DBG("multicast options: %s\n", p);
- p += 1 + inet_aton(p, &info->multicast.sin_addr);
- DBG("multicast ip = %@\n", info->multicast_ip);
- info->multicast.sin_port = strtoul(p, &p, 10);
- ++p;
- DBG("multicast port = %d\n",
- info->multicast.sin_port);
- state.ismaster = (*p == '1' ? 1 : 0);
- DBG("multicast ismaster = %d\n",
- state.ismaster);
- while (p < e && *p)
- p++;
- if (p < e)
- p++;
- }
+ rc = 1;
+ out:
+ if ( state.multicast.sin_addr.s_addr ) {
+ leave_group ( IGMP_SERVER );
}
- if (p > e)
- return 0;
- return i;
+ return rc;
}
static struct protocol tftm_protocol __protocol = {
.name = "x-tftm",
- .default_port = TFTM_PORT,
- .load = url_tftm,
+ .default_port = TFTP_PORT,
+ .load = tftm,
};
diff --git a/src/proto/tftp.c b/src/proto/tftp.c
index b154f5756..3f6bf35ab 100644
--- a/src/proto/tftp.c
+++ b/src/proto/tftp.c
@@ -1,169 +1,159 @@
#include "etherboot.h"
-#include "in.h"
-#include "nic.h"
#include "proto.h"
+#include "errno.h"
#include "tftp.h"
+#include "tftpcore.h"
-/* Utility function for tftp_block() */
-static int await_tftp ( int ival, void *ptr __unused,
- unsigned short ptype __unused, struct iphdr *ip,
- struct udphdr *udp, struct tcphdr *tcp __unused ) {
- if ( ! udp ) {
- return 0;
+/** @file
+ *
+ * TFTP protocol
+ */
+
+/**
+ * Process a TFTP block
+ *
+ * @v state TFTP transfer state
+ * @v tftp_state::block Last received data block
+ * @v tftp_state::blksize Transfer block size
+ * @v data The data block to process
+ * @v buffer The buffer to fill with the data
+ * @ret True Block processed successfully
+ * @ret False Block not processed successfully
+ * @ret tftp_state::block Incremented if applicable
+ * @ret *eof End-of-file marker
+ * @err #PXENV_STATUS_TFTP_INVALID_PACKET_SIZE Packet is too large
+ * @err other As returned by fill_buffer()
+ *
+ * Process a TFTP DATA packet that has been received. If the data
+ * packet is the next data packet in the stream, its contents will be
+ * placed in the #buffer and tftp_state::block will be incremented.
+ * If the packet is the final packet, end-of-file will be indicated
+ * via #eof.
+ *
+ * If the data packet is a duplicate, then process_tftp_data() will
+ * still return True, though nothing will be done with the packet. A
+ * False return value always indicates an error that should abort the
+ * transfer.
+ */
+static inline int tftp_process_data ( struct tftp_state *state,
+ struct tftp_data *data,
+ struct buffer *buffer,
+ int *eof ) {
+ unsigned int blksize;
+
+ /* Check it's the correct DATA block */
+ if ( ntohs ( data->block ) != ( state->block + 1 ) ) {
+ DBG ( "TFTP: got block %d, wanted block %d\n",
+ ntohs ( data->block ), state->block + 1 );
+ return 1;
}
- if ( arptable[ARP_CLIENT].ipaddr.s_addr != ip->dest.s_addr )
+ /* Check it's an acceptable size */
+ blksize = ( ntohs ( data->udp.len )
+ + offsetof ( typeof ( *data ), udp )
+ - offsetof ( typeof ( *data ), data ) );
+ if ( blksize > state->blksize ) {
+ DBG ( "TFTP: oversized block size %d (max %d)\n",
+ blksize, state->blksize );
+ errno = PXENV_STATUS_TFTP_INVALID_PACKET_SIZE;
return 0;
- if ( ntohs ( udp->dest ) != ival )
+ }
+ /* Place block in the buffer */
+ if ( ! fill_buffer ( buffer, data->data, state->block * state->blksize,
+ blksize ) ) {
+ DBG ( "TFTP: could not place data in buffer: %m\n" );
return 0;
+ }
+ /* Increment block counter */
+ state->block++;
+ /* Set EOF marker */
+ *eof = ( blksize < state->blksize );
return 1;
}
-/*
- * Download a single block via TFTP. This function is non-static so
- * that pxe_export.c can call it.
+/**
+ * Download a file via TFTP
+ *
+ * @v server TFTP server
+ * @v file File name
+ * @v buffer Buffer into which to load file
+ * @ret True File was downloaded successfully
+ * @ret False File was not downloaded successfully
+ * @err #PXENV_STATUS_TFTP_UNKNOWN_OPCODE Unknown type of TFTP block received
+ * @err other As returned by tftp_open()
+ * @err other As returned by tftp_process_opts()
+ * @err other As returned by tftp_ack()
+ * @err other As returned by tftp_process_data()
*
+ * Download a file from a TFTP server into the specified buffer.
*/
-int tftp_block ( struct tftpreq_info_t *request,
- struct tftpblk_info_t *block ) {
- static struct sockaddr_in server;
- static unsigned short lport = 2000; /* local port */
- struct tftp_t *rcvd = NULL;
- static struct tftpreq_t xmit;
- static unsigned short xmitlen = 0;
- static unsigned short blockidx = 0; /* Last block received */
- static unsigned short retry = 0; /* Retry attempts on last block */
- static int blksize = 0;
- unsigned short recvlen = 0;
+static int tftp ( char *url __unused, struct sockaddr_in *server, char *file,
+ struct buffer *buffer ) {
+ struct tftp_state state;
+ union tftp_any *reply;
+ int eof = 0;
- /* If this is a new request (i.e. if name is set), fill in
- * transmit block with RRQ and send it.
- */
- if ( request ) {
- rx_qdrain(); /* Flush receive queue */
- xmit.opcode = htons(TFTP_RRQ);
- xmitlen = (void*)&xmit.u.rrq - (void*)&xmit +
- sprintf((char*)xmit.u.rrq, "%s%coctet%cblksize%c%d",
- request->name, 0, 0, 0, request->blksize)
- + 1; /* null terminator */
- blockidx = 0; /* Reset counters */
- retry = 0;
- blksize = TFTP_DEFAULTSIZE_PACKET;
- lport++; /* Use new local port */
- server = *(request->server);
- if ( !udp_transmit(server.sin_addr.s_addr, lport,
- server.sin_port, xmitlen, &xmit) )
- return (0);
+ /* Initialise TFTP state */
+ memset ( &state, 0, sizeof ( state ) );
+ state.server = *server;
+
+ /* Open the file */
+ if ( ! tftp_open ( &state, file, &reply, 0 ) ) {
+ DBG ( "TFTP: could not open %@:%d/%s : %m\n",
+ server->sin_addr.s_addr, server->sin_port, file );
+ return 0;
}
- /* Exit if no transfer in progress */
- if ( !blksize ) return (0);
- /* Loop to wait until we get a packet we're interested in */
- block->data = NULL; /* Used as flag */
- while ( block->data == NULL ) {
- long timeout = rfc2131_sleep_interval ( blockidx ? TFTP_REXMT :
- TIMEOUT, retry );
- if ( !await_reply(await_tftp, lport, NULL, timeout) ) {
- /* No packet received */
- if ( retry++ > MAX_TFTP_RETRIES ) break;
- /* Retransmit last packet */
- if ( !blockidx ) lport++; /* New lport if new RRQ */
- if ( !udp_transmit(server.sin_addr.s_addr, lport,
- server.sin_port, xmitlen, &xmit) )
- return (0);
- continue; /* Back to waiting for packet */
- }
- /* Packet has been received */
- rcvd = (struct tftp_t *)&nic.packet[ETH_HLEN];
- recvlen = ntohs(rcvd->udp.len) - sizeof(struct udphdr)
- - sizeof(rcvd->opcode);
- server.sin_port = ntohs(rcvd->udp.src);
- retry = 0; /* Reset retry counter */
- switch ( htons(rcvd->opcode) ) {
- case TFTP_ERROR : {
- printf ( "TFTP error %d (%s)\n",
- ntohs(rcvd->u.err.errcode),
- rcvd->u.err.errmsg );
- return (0); /* abort */
- }
- case TFTP_OACK : {
- const char *p = rcvd->u.oack.data;
- const char *e = p + recvlen - 10; /* "blksize\0\d\0" */
-
- *((char*)(p+recvlen-1)) = '\0'; /* Force final 0 */
- if ( blockidx || !request ) break; /* Too late */
- if ( recvlen <= TFTP_MAX_PACKET ) /* sanity */ {
- /* Check for blksize option honoured */
- while ( p < e ) {
- if ( strcasecmp("blksize",p) == 0 &&
- p[7] == '\0' ) {
- blksize = strtoul(p+8,&p,10);
- p++; /* skip null */
- }
- while ( *(p++) ) {};
- }
+
+ /* Fetch file, a block at a time */
+ while ( 1 ) {
+ twiddle();
+ switch ( ntohs ( reply->common.opcode ) ) {
+ case TFTP_DATA:
+ if ( ! tftp_process_data ( &state, &reply->data,
+ buffer, &eof ) ) {
+ tftp_error ( &state, TFTP_ERR_ILLEGAL_OP,
+ NULL );
+ return 0;
+ }
+ break;
+ case TFTP_OACK:
+ if ( state.block ) {
+ /* OACK must be first block, if present */
+ DBG ( "TFTP: OACK after block %d\n",
+ state.block );
+ errno = PXENV_STATUS_TFTP_UNKNOWN_OPCODE;
+ tftp_error ( &state, TFTP_ERR_ILLEGAL_OP,
+ NULL );
+ return 0;
}
- if ( blksize < TFTP_DEFAULTSIZE_PACKET ||
- blksize > request->blksize ) {
- /* Incorrect blksize - error and abort */
- xmit.opcode = htons(TFTP_ERROR);
- xmit.u.err.errcode = 8;
- xmitlen = (void*)&xmit.u.err.errmsg
- - (void*)&xmit
- + sprintf((char*)xmit.u.err.errmsg,
- "RFC1782 error")
- + 1;
- udp_transmit(server.sin_addr.s_addr, lport,
- server.sin_port, xmitlen, &xmit);
- return (0);
+ if ( ! tftp_process_opts ( &state, &reply->oack ) ) {
+ DBG ( "TFTP: option processing failed: %m\n" );
+ tftp_error ( &state, TFTP_ERR_BAD_OPTS, NULL );
+ return 0;
}
- } break;
- case TFTP_DATA :
- if ( ntohs(rcvd->u.data.block) != ( blockidx + 1 ) )
- break; /* Re-ACK last block sent */
- if ( recvlen > ( blksize+sizeof(rcvd->u.data.block) ) )
- break; /* Too large; ignore */
- block->data = rcvd->u.data.download;
- block->block = ++blockidx;
- block->len = recvlen - sizeof(rcvd->u.data.block);
- block->eof = ( (unsigned short)block->len < blksize );
- /* If EOF, zero blksize to indicate transfer done */
- if ( block->eof ) blksize = 0;
break;
- default: break; /* Do nothing */
+ default:
+ DBG ( "TFTP: unexpected opcode %d\n",
+ ntohs ( reply->common.opcode ) );
+ errno = PXENV_STATUS_TFTP_UNKNOWN_OPCODE;
+ tftp_error ( &state, TFTP_ERR_ILLEGAL_OP, NULL );
+ return 0;
+ }
+ /* If we have reached EOF, stop here */
+ if ( eof )
+ break;
+ /* Fetch the next data block */
+ if ( ! tftp_ack ( &state, &reply ) ) {
+ DBG ( "TFTP: could not get next block: %m\n" );
+ if ( ! reply ) {
+ tftp_error ( &state, TFTP_ERR_ILLEGAL_OP,
+ NULL );
+ }
+ return 0;
}
- /* Send ACK */
- xmit.opcode = htons(TFTP_ACK);
- xmit.u.ack.block = htons(blockidx);
- xmitlen = TFTP_MIN_PACKET;
- udp_transmit ( server.sin_addr.s_addr, lport, server.sin_port,
- xmitlen, &xmit );
}
- return ( block->data ? 1 : 0 );
-}
-
-/*
- * Download a file via TFTP
- *
- */
-int tftp ( char *url __unused, struct sockaddr_in *server, char *file,
- struct buffer *buffer ) {
- struct tftpreq_info_t request_data = {
- .server = server,
- .name = file,
- .blksize = TFTP_MAX_PACKET,
- };
- struct tftpreq_info_t *request = &request_data;
- struct tftpblk_info_t block;
- off_t offset = 0;
- do {
- if ( ! tftp_block ( request, &block ) )
- return 0;
- if ( ! fill_buffer ( buffer, block.data, offset, block.len ) )
- return 0;
- twiddle();
- offset += block.len;
- request = NULL; /* Send request only once */
- } while ( ! block.eof );
+ /* ACK the final packet, as a courtesy to the server */
+ tftp_ack_nowait ( &state );
return 1;
}
diff --git a/src/proto/tftpcore.c b/src/proto/tftpcore.c
new file mode 100644
index 000000000..511c68599
--- /dev/null
+++ b/src/proto/tftpcore.c
@@ -0,0 +1,541 @@
+#include "tftp.h"
+#include "tcp.h" /* for struct tcphdr */
+#include "errno.h"
+#include "etherboot.h"
+#include "tftpcore.h"
+
+/** @file */
+
+/**
+ * await_reply() filter for TFTP packets
+ *
+ * @v ptr Pointer to a struct tftp_state
+ * @v tftp_state::server::sin_addr TFTP server IP address
+ * @v tftp_state::lport Client UDP port
+ * @v tftp_state::multicast::sin_addr Multicast IP address, or 0.0.0.0
+ * @v tftp_state::multicast::sin_port Multicast UDP port, or 0
+ * @v ip IP header
+ * @v udp UDP header
+ * @ret True This is our TFTP packet
+ * @ret False This is not one of our TFTP packets
+ *
+ * Wait for a TFTP packet that is part of the current connection
+ * (i.e. comes from the TFTP server, has the correct destination port,
+ * and is addressed either to our IP address and UDP port, or to our
+ * multicast listening address and UDP port).
+ *
+ * Use await_tftp() in code such as
+ *
+ * @code
+ *
+ * if ( await_reply ( await_tftp, 0, &tftp_state, timeout ) ) {
+ * ...
+ * }
+ *
+ * @endcode
+ */
+static int await_tftp ( int ival __unused, void *ptr,
+ unsigned short ptype __unused, struct iphdr *ip,
+ struct udphdr *udp, struct tcphdr *tcp __unused ) {
+ struct tftp_state *state = ptr;
+
+ /* Must have valid UDP (and, therefore, also IP) headers */
+ if ( ! udp ) {
+ DBG2 ( "TFTPCORE: not UDP\n" );
+ return 0;
+ }
+ /* Packet must come from the TFTP server */
+ if ( ip->src.s_addr != state->server.sin_addr.s_addr ) {
+ DBG2 ( "TFTPCORE: from %@, not from TFTP server %@\n",
+ ip->src.s_addr, state->server.sin_addr.s_addr );
+ return 0;
+ }
+ /* Packet may be addressed to our IP address and unicast UDP
+ * port
+ */
+ if ( ( ip->dest.s_addr == arptable[ARP_CLIENT].ipaddr.s_addr ) &&
+ ( ntohs ( udp->dest ) == state->lport ) ) {
+ return 1;
+ }
+ /* Packet may be addressed to our multicast IP address and UDP
+ * port, if we have one
+ */
+ if ( ( state->multicast.sin_addr.s_addr ) &&
+ ( ip->dest.s_addr == state->multicast.sin_addr.s_addr ) &&
+ ( ntohs ( udp->dest ) == state->multicast.sin_port ) ) {
+ return 1;
+ }
+ DBG2 ( "TFTPCORE: to %@:%d, not to %@:%d (or %@:%d)\n",
+ ip->dest.s_addr, ntohs ( udp->dest ),
+ arptable[ARP_CLIENT].ipaddr.s_addr, state->lport,
+ state->multicast.sin_addr.s_addr, state->multicast.sin_port );
+ return 0;
+}
+
+/**
+ * Retrieve a TFTP packet
+ *
+ * @v state TFTP transfer state
+ * @v tftp_state::server::sin_addr TFTP server IP address
+ * @v tftp_state::lport Client UDP port
+ * @v tftp_state::multicast::sin_addr Multicast IP address, or 0.0.0.0
+ * @v tftp_state::multicast::sin_port Multicast UDP port, or 0
+ * @v timeout Time to wait for a response
+ * @ret True Received a non-error response
+ * @ret False Received error response / no response
+ * @ret *reply The server's response, if any
+ * @err #PXENV_STATUS_TFTP_READ_TIMEOUT No response received in time
+ * @err other As set by tftp_set_errno()
+ *
+ * Retrieve the next packet sent by the TFTP server, if any is sent
+ * within the specified timeout period. The packet is returned via
+ * #reply. If no packet is received within the timeout period, a NULL
+ * value will be stored in #reply.
+ *
+ * If the response from the server is a TFTP ERROR packet, tftp_get()
+ * will return False and #errno will be set accordingly.
+ *
+ * You can differentiate between "received no response" and "received
+ * an error response" by checking #reply; if #reply is NULL then no
+ * response was received.
+ */
+int tftp_get ( struct tftp_state *state, long timeout,
+ union tftp_any **reply ) {
+
+ *reply = NULL;
+
+ if ( ! await_reply ( await_tftp, 0, state, timeout ) ) {
+ errno = PXENV_STATUS_TFTP_READ_TIMEOUT;
+ return 0;
+ }
+
+ *reply = ( union tftp_any * ) &nic.packet[ETH_HLEN];
+ DBG ( "TFTPCORE: got reply (type %d)\n",
+ ntohs ( (*reply)->common.opcode ) );
+ if ( ntohs ( (*reply)->common.opcode ) == TFTP_ERROR ){
+ tftp_set_errno ( &(*reply)->error );
+ return 0;
+ }
+ return 1;
+}
+
+/**
+ * Issue a TFTP open request (RRQ)
+ *
+ * @v state TFTP transfer state
+ * @v tftp_state::server::sin_addr TFTP server IP address
+ * @v tftp_state::server::sin_port TFTP server UDP port, or 0
+ * @v tftp_state::lport Client UDP port, or 0
+ * @v tftp_state::multicast::sin_addr Multicast IP address, or 0.0.0.0
+ * @v tftp_state::multicast::sin_port Multicast UDP port, or 0
+ * @v tftp_state::blksize Requested blksize, or 0
+ * @v filename File name
+ * @v multicast Enable/disable rfc2090 multicast TFTP
+ * @ret True Received a non-error response
+ * @ret False Received error response / no response
+ * @ret tftp_state::server::sin_port TFTP server UDP port
+ * @ret tftp_state::lport Client UDP port
+ * @ret tftp_state::blksize Always #TFTP_DEFAULT_BLKSIZE
+ * @ret *reply The server's response, if any
+ * @err #PXENV_STATUS_TFTP_OPEN_TIMEOUT TFTP open timed out
+ * @err other As returned by udp_transmit()
+ * @err other As set by tftp_set_errno()
+ *
+ * Send a TFTP/TFTM/MTFTP RRQ (read request) to a TFTP server, and
+ * return the server's reply (which may be an OACK, DATA or ERROR
+ * packet). The server's reply will not be acknowledged, or processed
+ * in any way.
+ *
+ * If tftp_state::server::sin_port is 0, the standard TFTP server port
+ * (#TFTP_PORT) will be used.
+ *
+ * If tftp_state::lport is 0, the standard mechanism of
+ * using a new, unique port number for each TFTP request will be used.
+ *
+ * If tftp_state::multicast::sin_addr is not 0.0.0.0, it (and
+ * tftp_state::multicast::sin_port) will be used as a multicast
+ * listening address for replies from the TFTP server.
+ *
+ * For the various different types of TFTP server, you should treat
+ * tftp_state::lport and tftp_state::multicast as follows:
+ *
+ * - Standard TFTP server: set tftp_state::lport to 0,
+ * tftp_state::multicast::sin_addr to 0.0.0.0 and
+ * tftp_state::multicast::sin_port to 0. tftp_open() will set
+ * tftp_state::lport to the assigned local UDP port.
+ *
+ * - TFTM server: set tftp_state::lport to 0,
+ * tftp_state::multicast::sin_addr to 0.0.0.0 and
+ * tftp_state::multicast::sin_port to 0. tftp_open() will set
+ * tftp_state::lport to the assigned local UDP port. (Your call
+ * to tftp_process_opts() will then overwrite both
+ * tftp_state::multicast::sin_addr and
+ * tftp_state::multicast::sin_port with the values specified in
+ * the OACK packet.)
+ *
+ * - MTFTP server: set tftp_state::multicast::sin_addr to the
+ * multicast address and both tftp_state::lport and
+ * tftp_state::multicast::sin_port to the multicast port (both of
+ * which must be previously known, e.g. provided by a DHCP
+ * server). tftp_open() will not alter these values.
+ *
+ * If tftp_state::blksize is 0, the maximum blocksize
+ * (#TFTP_MAX_BLKSIZE) will be requested.
+ *
+ * On exit, tftp_state::blksize will always contain
+ * #TFTP_DEFAULT_BLKSIZE, since this is the blocksize value that must
+ * be assumed until the OACK packet is processed (by a subsequent call
+ * to tftp_process_opts()).
+ *
+ * tftp_state::server::sin_port will be set to the UDP port from which
+ * the server's response originated. This may or may not be the port
+ * to which the open request was sent.
+ *
+ * The options "blksize" and "tsize" will always be appended to a TFTP
+ * open request. The option "multicast" will be appended to the
+ * request if #multicast is True. Servers that do not understand any
+ * of these options should simply ignore them.
+ *
+ * tftp_open() will not automatically join or leave multicast groups;
+ * the caller is responsible for calling join_group() and
+ * leave_group() at appropriate times.
+ *
+ * If the response from the server is a TFTP ERROR packet, tftp_open()
+ * will return False and #errno will be set accordingly.
+ */
+int tftp_open ( struct tftp_state *state, const char *filename,
+ union tftp_any **reply, int multicast ) {
+ static unsigned short lport = 2000; /* local port */
+ int fixed_lport;
+ struct tftp_rrq rrq;
+ char *p;
+ unsigned int rrqlen;
+ int retry;
+
+ /* Flush receive queue */
+ rx_qdrain();
+
+ /* Default to blksize of TFTP_MAX_BLKSIZE if none specified */
+ if ( ! state->blksize )
+ state->blksize = TFTP_MAX_BLKSIZE;
+
+ /* Use default TFTP server port if none specified */
+ if ( ! state->server.sin_port )
+ state->server.sin_port = TFTP_PORT;
+
+ /* Determine whether or not to use lport */
+ fixed_lport = state->lport;
+
+ /* Set up RRQ */
+ rrq.opcode = htons ( TFTP_RRQ );
+ p = rrq.data;
+ p += sprintf ( p, "%s%coctet%cblksize%c%d%ctsize%c0",
+ filename, 0, 0, 0, state->blksize, 0, 0 ) + 1;
+ if ( multicast ) {
+ p += sprintf ( p, "multicast%c", 0 ) + 1;
+ }
+ rrqlen = ( p - ( char * ) &rrq );
+
+ /* Set negotiated blksize to default value */
+ state->blksize = TFTP_DEFAULT_BLKSIZE;
+
+ /* Nullify received packet pointer */
+ *reply = NULL;
+
+ /* Transmit RRQ until we get a response */
+ for ( retry = 0 ; retry < MAX_TFTP_RETRIES ; retry++ ) {
+ long timeout = rfc2131_sleep_interval ( TIMEOUT, retry );
+
+ /* Set client UDP port, if not already fixed */
+ if ( ! fixed_lport )
+ state->lport = ++lport;
+
+ /* Send the RRQ */
+ DBG ( "TFTPCORE: requesting %@:%d/%s from port %d\n",
+ state->server.sin_addr.s_addr, state->server.sin_port,
+ rrq.data, state->lport );
+ if ( ! udp_transmit ( state->server.sin_addr.s_addr,
+ state->lport, state->server.sin_port,
+ rrqlen, &rrq ) )
+ return 0;
+
+ /* Wait for response */
+ if ( tftp_get ( state, timeout, reply ) ) {
+ /* We got a non-error response */
+ state->server.sin_port
+ = ntohs ( (*reply)->common.udp.src );
+ DBG ( "TFTP server is at %@:%d\n",
+ state->server.sin_addr.s_addr,
+ state->server.sin_port );
+ return 1;
+ }
+ if ( *reply ) {
+ /* We got an error response; abort */
+ return 0;
+ }
+ }
+
+ DBG ( "TFTPCORE: open request timed out\n" );
+ errno = PXENV_STATUS_TFTP_OPEN_TIMEOUT;
+ return 0;
+}
+
+/**
+ * Process a TFTP OACK packet
+ *
+ * @v state TFTP transfer state
+ * @v oack The TFTP OACK packet
+ * @ret True Options were processed successfully
+ * @ret False Options were not processed successfully
+ * @ret tftp_state::blksize Negotiated blksize
+ * @ret tftp_state::tsize File size (if known), or 0
+ * @ret tftp_state::multicast::sin_addr Multicast IP address, or 0.0.0.0
+ * @ret tftp_state::multicast::sin_port Multicast UDP port, or 0
+ * @ret tftp_state::master Client is master
+ * @err EINVAL An invalid option value was encountered
+ *
+ * Process the options returned by the TFTP server in an rfc2347 OACK
+ * packet. The options "blksize" (rfc2348), "tsize" (rfc2349) and
+ * "multicast" (rfc2090) are recognised and processed; any other
+ * options are silently ignored.
+ *
+ * Where an option is not present in the OACK packet, the
+ * corresponding field(s) in #state will be left unaltered.
+ *
+ * Calling tftp_process_opts() does not send an acknowledgement for
+ * the OACK packet; this is the responsibility of the caller.
+ *
+ * @note If the "blksize" option is not present, tftp_state::blksize
+ * will @b not be implicitly set to #TFTP_DEFAULT_BLKSIZE. However,
+ * since tftp_open() always sets tftp_state::blksize to
+ * #TFTP_DEFAULT_BLKSIZE before returning, you probably don't need to
+ * worry about this.
+ */
+int tftp_process_opts ( struct tftp_state *state, struct tftp_oack *oack ) {
+ const char *p;
+ const char *end;
+
+ DBG ( "TFTPCORE: processing OACK\n" );
+
+ /* End of options */
+ end = ( ( char * ) &oack->udp ) + ntohs ( oack->udp.len );
+
+ /* Only possible error */
+ errno = EINVAL;
+
+ for ( p = oack->data ; p < end ; ) {
+ if ( strcasecmp ( "blksize", p ) == 0 ) {
+ p += 8;
+ state->blksize = strtoul ( p, &p, 10 );
+ if ( *p ) {
+ DBG ( "TFTPCORE: garbage \"%s\" "
+ "after blksize\n", p );
+ return 0;
+ }
+ p++;
+ DBG ( "TFTPCORE: got blksize %d\n", state->blksize );
+ } else if ( strcasecmp ( "tsize", p ) == 0 ) {
+ p += 6;
+ state->tsize = strtoul ( p, &p, 10 );
+ if ( *p ) {
+ DBG ( "TFTPCORE: garbage \"%s\" "
+ "after tsize\n", p );
+ return 0;
+ }
+ p++;
+ DBG ( "TFTPCORE: got tsize %d\n", state->tsize );
+ } else if ( strcasecmp ( "multicast", p ) == 0 ) {
+ p += 10;
+ char *e = strchr ( p, ',' );
+ if ( ( ! e ) || ( e >= end ) ) {
+ DBG ( "TFTPCORE: malformed multicast field "
+ "\"%s\"\n", p );
+ return 0;
+ }
+ /* IP address may be missing, in which case we
+ * should leave state->multicast.sin_addr
+ * unaltered.
+ */
+ if ( e != p ) {
+ int rc;
+ *e = '\0';
+ rc = inet_aton ( p,
+ &state->multicast.sin_addr );
+ *e = ',';
+ if ( ! rc ) {
+ DBG ( "TFTPCORE: malformed multicast "
+ "IP address \"%s\"\n", p );
+ return 0;
+ }
+ }
+ p = e + 1;
+ /* UDP port may also be missing */
+ if ( *p != ',' ) {
+ state->multicast.sin_port
+ = strtoul ( p, &p, 10 );
+ if ( *p != ',' ) {
+ DBG ( "TFTPCORE: garbage \"%s\" "
+ "after multicast port\n", p );
+ return 0;
+ }
+ }
+ p++;
+ /* "Master Client" must always be present */
+ state->master = strtoul ( p, &p, 10 );
+ if ( *p ) {
+ DBG ( "TFTPCORE: garbage \"%s\" "
+ "after multicast mc\n", p );
+ return 0;
+ }
+ p++;
+ DBG ( "TFTPCORE: got multicast %@:%d (%s)\n",
+ state->multicast.sin_addr.s_addr,
+ state->multicast.sin_port,
+ ( state->master ? "master" : "not master" ) );
+ } else {
+ DBG ( "TFTPCORE: unknown option \"%s\"\n", p );
+ p += strlen ( p ) + 1; /* skip option name */
+ p += strlen ( p ) + 1; /* skip option value */
+ }
+ }
+
+ if ( p > end ) {
+ DBG ( "TFTPCORE: overran options in OACK\n" );
+ return 0;
+ }
+
+ return 1;
+}
+
+/**
+ * Acknowledge a TFTP packet
+ *
+ * @v state TFTP transfer state
+ * @v tftp_state::server::sin_addr TFTP server IP address
+ * @v tftp_state::server::sin_port TFTP server UDP port
+ * @v tftp_state::lport Client UDP port
+ * @v tftp_state::block Most recently received block number
+ * @ret True Acknowledgement packet was sent
+ * @ret False Acknowledgement packet was not sent
+ * @err other As returned by udp_transmit()
+ *
+ * Send a TFTP ACK packet for the most recently received block.
+ *
+ * This sends only a single ACK packet; it does not wait for the
+ * server's response.
+ */
+int tftp_ack_nowait ( struct tftp_state *state ) {
+ struct tftp_ack ack;
+
+ DBG ( "TFTPCORE: acknowledging data block %d\n", state->block );
+ ack.opcode = htons ( TFTP_ACK );
+ ack.block = htons ( state->block );
+ return udp_transmit ( state->server.sin_addr.s_addr,
+ state->lport, state->server.sin_port,
+ sizeof ( ack ), &ack );
+}
+
+/**
+ * Acknowledge a TFTP packet and wait for a response
+ *
+ * @v state TFTP transfer state
+ * @v tftp_state::server::sin_addr TFTP server IP address
+ * @v tftp_state::server::sin_port TFTP server UDP port
+ * @v tftp_state::lport Client UDP port
+ * @v tftp_state::block Most recently received block number
+ * @ret True Received a non-error response
+ * @ret False Received error response / no response
+ * @ret *reply The server's response, if any
+ * @err #PXENV_STATUS_TFTP_READ_TIMEOUT Timed out waiting for a response
+ * @err other As returned by tftp_ack_nowait()
+ * @err other As set by tftp_set_errno()
+ *
+ * Send a TFTP ACK packet for the most recently received data block,
+ * and keep transmitting this ACK until we get a response from the
+ * server (e.g. a new data block).
+ *
+ * If the response is a TFTP DATA packet, no processing is done.
+ * Specifically, the block number is not checked to ensure that this
+ * is indeed the next data block in the sequence, nor is
+ * tftp_state::block updated with the new block number.
+ *
+ * If the response from the server is a TFTP ERROR packet, tftp_open()
+ * will return False and #errno will be set accordingly.
+ */
+int tftp_ack ( struct tftp_state *state, union tftp_any **reply ) {
+ int retry;
+
+ *reply = NULL;
+ for ( retry = 0 ; retry < MAX_TFTP_RETRIES ; retry++ ) {
+ long timeout = rfc2131_sleep_interval ( TFTP_REXMT, retry );
+ /* ACK the last data block */
+ if ( ! tftp_ack_nowait ( state ) ) {
+ DBG ( "TFTP: could not send ACK: %m\n" );
+ return 0;
+ }
+ if ( tftp_get ( state, timeout, reply ) ) {
+ /* We got a non-error response */
+ return 1;
+ }
+ if ( *reply ) {
+ /* We got an error response */
+ return 0;
+ }
+ }
+ DBG ( "TFTP: timed out during read\n" );
+ errno = PXENV_STATUS_TFTP_READ_TIMEOUT;
+ return 0;
+}
+
+/**
+ * Send a TFTP error
+ *
+ * @v state TFTP transfer state
+ * @v tftp_state::server::sin_addr TFTP server IP address
+ * @v tftp_state::server::sin_port TFTP server UDP port
+ * @v tftp_state::lport Client UDP port
+ * @v errcode TFTP error code
+ * @v errmsg Descriptive error string, or NULL
+ * @ret True Error packet was sent
+ * @ret False Error packet was not sent
+ *
+ * Send a TFTP ERROR packet back to the server to terminate the
+ * transfer.
+ *
+ * If #errmsg is NULL, the current error message string as returned by
+ * strerror(errno) will be used as the error text.
+ */
+int tftp_error ( struct tftp_state *state, int errcode, const char *errmsg ) {
+ struct tftp_error error;
+
+ DBG ( "TFTPCORE: aborting with error %d (%s)\n", errcode, errmsg );
+ error.opcode = htons ( TFTP_ERROR );
+ error.errcode = htons ( errcode );
+ strncpy ( error.errmsg, errmsg ? errmsg : strerror ( errno ),
+ sizeof ( error.errmsg ) );
+ return udp_transmit ( state->server.sin_addr.s_addr,
+ state->lport, state->server.sin_port,
+ sizeof ( error ), &error );
+}
+
+/**
+ * Interpret a TFTP error
+ *
+ * @v error Pointer to a struct tftp_error
+ *
+ * Sets #errno based on the error code in a TFTP ERROR packet.
+ */
+void tftp_set_errno ( struct tftp_error *error ) {
+ static int errmap[] = {
+ [TFTP_ERR_FILE_NOT_FOUND] = PXENV_STATUS_TFTP_FILE_NOT_FOUND,
+ [TFTP_ERR_ACCESS_DENIED] = PXENV_STATUS_TFTP_ACCESS_VIOLATION,
+ [TFTP_ERR_ILLEGAL_OP] = PXENV_STATUS_TFTP_UNKNOWN_OPCODE,
+ };
+ unsigned int errcode = ntohs ( error->errcode );
+
+ errno = 0;
+ if ( errcode < ( sizeof(errmap) / sizeof(errmap[0]) ) )
+ errno = errmap[errcode];
+ if ( ! errno )
+ errno = PXENV_STATUS_TFTP_ERROR_OPCODE;
+}
diff --git a/src/util/makerom.pl b/src/util/makerom.pl
index 695468c26..9d751e190 100755
--- a/src/util/makerom.pl
+++ b/src/util/makerom.pl
@@ -157,7 +157,7 @@ sub makerom () {
# If PXE image, just fill the length field and write it out
if ($opts{'x'}) {
substr($rom, 2, 1) = chr((length($rom) + 511) / 512);
- &writerom($ARGV[0], \$rom);
+ writerom($ARGV[0], \$rom);
return;
}
# Size specified with -s overrides value in 3rd byte in image
@@ -168,7 +168,7 @@ sub makerom () {
$romsize = ($filesize + 511) & ~511
}
} else {
- $romsize = &getromsize(\$rom);
+ $romsize = getromsize(\$rom);
# 0 put there by *loader.S means makerom should pick the size
if ($romsize == 0) {
# Shrink romsize down to the smallest power of two that will do
@@ -190,14 +190,16 @@ sub makerom () {
}
substr($rom, 2, 1) = chr(($romsize / 512) % 256);
print "ROM size is $romsize\n" if $opts{'v'};
- my $identoffset = &addident(\$rom);
- &pcipnpheaders(\$rom, $identoffset);
- &undiheaders(\$rom);
+ # set the product string only if we don't have one yet
+ my $pnp_hdr_offset = unpack('v', substr($rom, PNP_PTR_LOC, 2));
+ my $identoffset = substr($rom, $pnp_hdr_offset+PNP_DEVICE_OFF, 2) eq "\0\0" ? addident(\$rom) : undef;
+ pcipnpheaders(\$rom, $identoffset);
+ undiheaders(\$rom);
# 3c503 requires last two bytes to be 0x80
substr($rom, MINROMSIZE-2, 2) = "\x80\x80"
if ($opts{'3'} and $romsize == MINROMSIZE);
- &checksum(\$rom);
- &writerom($ARGV[0], \$rom);
+ checksum(\$rom);
+ writerom($ARGV[0], \$rom);
}
sub modrom () {
@@ -211,16 +213,16 @@ sub modrom () {
close(R);
defined($filesize) and $filesize >= 3 or die "Cannot get first 3 bytes of file\n";
print "$filesize bytes read\n" if $opts{'v'};
- &pcipnpheaders(\$rom);
- &undiheaders(\$rom);
- &checksum(\$rom);
- &writerom($ARGV[0], \$rom);
+ pcipnpheaders(\$rom, undef);
+ undiheaders(\$rom);
+ checksum(\$rom);
+ writerom($ARGV[0], \$rom);
}
# Main routine. See how we were called and behave accordingly
if ($0 =~ m:modrom(\.pl)?$:) {
- &modrom();
+ modrom();
} else {
- &makerom();
+ makerom();
}
exit(0);