summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2008-12-12 14:36:02 -0800
committerH. Peter Anvin <hpa@zytor.com>2008-12-12 14:36:02 -0800
commitfde037048c728ae20464fbfb0a65b47879e74ac6 (patch)
tree328c191147f8d45f050cc5dacc15b73a43ea3d92
parent8b62a8c215613da1ed676cab8ce203d40160a620 (diff)
downloadsyslinux-broken1.tar.gz
gPXE: update to the "kkpxe" branchbroken1
Update gPXE to the "kkpxe" branch, an experimental branch of the gPXE tree which should let us eliminate the gpxelinux-specific hacks. Specifically, this corresponds to checkin 0963c883a9402bd5846e687a100e196f7e8a2ef7 of git://git.etherboot.org/scm/people/mcb30/gpxe.git. Signed-off-by: H. Peter Anvin <hpa@zytor.com>
-rw-r--r--gpxe/Makefile6
-rw-r--r--gpxe/VERSION2
-rw-r--r--gpxe/src/Makefile190
-rw-r--r--gpxe/src/Makefile.housekeeping438
-rw-r--r--gpxe/src/arch/i386/Config148
-rw-r--r--gpxe/src/arch/i386/Makefile136
-rw-r--r--gpxe/src/arch/i386/Makefile.efi24
-rw-r--r--gpxe/src/arch/i386/Makefile.pcbios55
-rw-r--r--gpxe/src/arch/i386/core/gdbidt.S2
-rw-r--r--gpxe/src/arch/i386/core/gdbmach.c2
-rw-r--r--gpxe/src/arch/i386/core/nap.c12
-rw-r--r--gpxe/src/arch/i386/core/pcidirect.c8
-rw-r--r--gpxe/src/arch/i386/core/pic8259.c1
-rw-r--r--gpxe/src/arch/i386/core/rdtsc_timer.c87
-rw-r--r--gpxe/src/arch/i386/core/relocate.c10
-rw-r--r--gpxe/src/arch/i386/core/start32.S325
-rw-r--r--gpxe/src/arch/i386/core/timer2.c (renamed from gpxe/src/arch/i386/core/i386_timer.c)24
-rw-r--r--gpxe/src/arch/i386/core/video_subr.c2
-rw-r--r--gpxe/src/arch/i386/core/virtaddr.S2
-rw-r--r--gpxe/src/arch/i386/core/x86_io.c94
-rw-r--r--gpxe/src/arch/i386/drivers/net/undinet.c66
-rw-r--r--gpxe/src/arch/i386/drivers/net/undionly.c18
-rw-r--r--gpxe/src/arch/i386/drivers/timer_bios.c57
-rw-r--r--gpxe/src/arch/i386/drivers/timer_rdtsc.c69
-rw-r--r--gpxe/src/arch/i386/firmware/pcbios/e820mangler.S12
-rw-r--r--gpxe/src/arch/i386/firmware/pcbios/gateA20.c13
-rw-r--r--gpxe/src/arch/i386/firmware/pcbios/hidemem.c32
-rw-r--r--gpxe/src/arch/i386/firmware/pcbios/memmap.c20
-rw-r--r--gpxe/src/arch/i386/firmware/pcbios/smbios_settings.c23
-rw-r--r--gpxe/src/arch/i386/image/multiboot.c6
-rw-r--r--gpxe/src/arch/i386/image/nbi.c7
-rw-r--r--gpxe/src/arch/i386/include/bios.h3
-rw-r--r--gpxe/src/arch/i386/include/biosint.h15
-rw-r--r--gpxe/src/arch/i386/include/bits/errfile.h2
-rw-r--r--gpxe/src/arch/i386/include/bits/io.h12
-rw-r--r--gpxe/src/arch/i386/include/bits/nap.h13
-rw-r--r--gpxe/src/arch/i386/include/bits/pci_io.h13
-rw-r--r--gpxe/src/arch/i386/include/bits/timer.h13
-rw-r--r--gpxe/src/arch/i386/include/bits/timer2.h8
-rw-r--r--gpxe/src/arch/i386/include/bits/uaccess.h8
-rw-r--r--gpxe/src/arch/i386/include/bits/umalloc.h12
-rw-r--r--gpxe/src/arch/i386/include/gpxe/bios_nap.h16
-rw-r--r--gpxe/src/arch/i386/include/gpxe/bios_timer.h42
-rw-r--r--gpxe/src/arch/i386/include/gpxe/efi/efix86_nap.h16
-rw-r--r--gpxe/src/arch/i386/include/gpxe/memtop_umalloc.h16
-rw-r--r--gpxe/src/arch/i386/include/gpxe/pcibios.h (renamed from gpxe/src/arch/i386/include/pcibios.h)55
-rw-r--r--gpxe/src/arch/i386/include/gpxe/pcidirect.h (renamed from gpxe/src/arch/i386/include/pcidirect.h)53
-rw-r--r--gpxe/src/arch/i386/include/gpxe/rdtsc_timer.h37
-rw-r--r--gpxe/src/arch/i386/include/gpxe/timer2.h12
-rw-r--r--gpxe/src/arch/i386/include/gpxe/x86_io.h151
-rw-r--r--gpxe/src/arch/i386/include/int13.h1
-rw-r--r--gpxe/src/arch/i386/include/io.h265
-rwxr-xr-x[-rw-r--r--]gpxe/src/arch/i386/include/librm.h303
-rw-r--r--gpxe/src/arch/i386/include/pci_io.h35
-rw-r--r--gpxe/src/arch/i386/include/pxe_addr.h17
-rw-r--r--gpxe/src/arch/i386/include/realmode.h93
-rw-r--r--gpxe/src/arch/i386/include/registers.h13
-rw-r--r--gpxe/src/arch/i386/include/undi.h10
-rw-r--r--gpxe/src/arch/i386/include/virtaddr.h105
-rw-r--r--gpxe/src/arch/i386/interface/efi/efix86_nap.c46
-rw-r--r--gpxe/src/arch/i386/interface/pcbios/bios_nap.c14
-rw-r--r--gpxe/src/arch/i386/interface/pcbios/bios_timer.c63
-rw-r--r--gpxe/src/arch/i386/interface/pcbios/biosint.c11
-rw-r--r--gpxe/src/arch/i386/interface/pcbios/memtop_umalloc.c (renamed from gpxe/src/arch/i386/core/umalloc.c)28
-rw-r--r--gpxe/src/arch/i386/interface/pcbios/pcibios.c (renamed from gpxe/src/arch/i386/core/pcibios.c)11
-rw-r--r--gpxe/src/arch/i386/interface/pxe/pxe_entry.S14
-rw-r--r--gpxe/src/arch/i386/prefix/dskprefix.S10
-rw-r--r--gpxe/src/arch/i386/prefix/efiprefix.S175
-rw-r--r--gpxe/src/arch/i386/prefix/hdprefix.S10
-rw-r--r--gpxe/src/arch/i386/prefix/kkpxeprefix.S8
-rw-r--r--gpxe/src/arch/i386/prefix/libprefix.S168
-rw-r--r--gpxe/src/arch/i386/prefix/lkrnprefix.S10
-rw-r--r--gpxe/src/arch/i386/prefix/nbiprefix.S13
-rw-r--r--gpxe/src/arch/i386/prefix/pxeprefix.S129
-rw-r--r--gpxe/src/arch/i386/prefix/romprefix.S162
-rw-r--r--gpxe/src/arch/i386/scripts/efi.lds180
-rw-r--r--gpxe/src/arch/i386/scripts/i386.lds279
-rwxr-xr-x[-rw-r--r--]gpxe/src/arch/i386/transitions/librm.S10
-rwxr-xr-x[-rw-r--r--]gpxe/src/arch/i386/transitions/librm_mgmt.c101
-rw-r--r--gpxe/src/config.h175
-rw-r--r--gpxe/src/config/.gitignore1
-rw-r--r--gpxe/src/config/console.h21
-rw-r--r--gpxe/src/config/defaults.h8
-rw-r--r--gpxe/src/config/defaults/efi.h20
-rw-r--r--gpxe/src/config/defaults/pcbios.h28
-rw-r--r--gpxe/src/config/general.h122
-rw-r--r--gpxe/src/config/ioapi.h15
-rw-r--r--gpxe/src/config/isa.h15
-rw-r--r--gpxe/src/config/nap.h15
-rw-r--r--gpxe/src/config/serial.h28
-rw-r--r--gpxe/src/config/timer.h15
-rw-r--r--gpxe/src/config/umalloc.h12
-rw-r--r--gpxe/src/core/config.c40
-rw-r--r--gpxe/src/core/console.c6
-rw-r--r--gpxe/src/core/debug.c2
-rw-r--r--gpxe/src/core/gdbudp.c2
-rw-r--r--gpxe/src/core/main.c16
-rw-r--r--gpxe/src/core/malloc.c2
-rw-r--r--gpxe/src/core/monojob.c7
-rw-r--r--gpxe/src/core/null_nap.c3
-rw-r--r--gpxe/src/core/nvo.c2
-rw-r--r--gpxe/src/core/pc_kbd.c2
-rw-r--r--gpxe/src/core/process.c2
-rw-r--r--gpxe/src/core/serial.c2
-rw-r--r--gpxe/src/core/settings.c20
-rw-r--r--gpxe/src/core/timer.c91
-rw-r--r--gpxe/src/core/uri.c8
-rw-r--r--gpxe/src/crypto/cryptoLayer.h2
-rw-r--r--gpxe/src/drivers/bitbash/i2c_bit.c147
-rw-r--r--gpxe/src/drivers/bus/eisa.c2
-rw-r--r--gpxe/src/drivers/bus/isa.c6
-rw-r--r--gpxe/src/drivers/bus/isapnp.c2
-rw-r--r--gpxe/src/drivers/bus/mca.c2
-rw-r--r--gpxe/src/drivers/infiniband/arbel.c160
-rw-r--r--gpxe/src/drivers/infiniband/hermon.c160
-rw-r--r--gpxe/src/drivers/infiniband/ib_packet.c234
-rw-r--r--gpxe/src/drivers/infiniband/ib_sma.c553
-rw-r--r--gpxe/src/drivers/infiniband/ib_smc.c166
-rw-r--r--gpxe/src/drivers/infiniband/linda.c2396
-rw-r--r--gpxe/src/drivers/infiniband/linda.h271
-rw-r--r--gpxe/src/drivers/infiniband/linda_fw.c1067
-rw-r--r--gpxe/src/drivers/infiniband/qib_7220_regs.h1763
-rw-r--r--gpxe/src/drivers/infiniband/qib_genbits.pl95
-rw-r--r--gpxe/src/drivers/net/3c509.c2
-rw-r--r--gpxe/src/drivers/net/3c595.c2
-rw-r--r--gpxe/src/drivers/net/3c90x.c4
-rw-r--r--gpxe/src/drivers/net/cs89x0.c4
-rw-r--r--gpxe/src/drivers/net/e1000/e1000.h3
-rw-r--r--gpxe/src/drivers/net/e1000/e1000_osdep.h50
-rw-r--r--gpxe/src/drivers/net/eepro100.c8
-rw-r--r--gpxe/src/drivers/net/epic100.c4
-rw-r--r--gpxe/src/drivers/net/etherfabric.c5484
-rw-r--r--gpxe/src/drivers/net/etherfabric_nic.h201
-rw-r--r--gpxe/src/drivers/net/forcedeth.c2
-rw-r--r--gpxe/src/drivers/net/ipoib.c565
-rw-r--r--gpxe/src/drivers/net/natsemi.c3
-rw-r--r--gpxe/src/drivers/net/ne2k_isa.c373
-rw-r--r--gpxe/src/drivers/net/phantom/phantom.c1499
-rw-r--r--gpxe/src/drivers/net/phantom/phantom.h155
-rw-r--r--gpxe/src/drivers/net/pnic.c2
-rw-r--r--gpxe/src/drivers/net/r8169.c3099
-rw-r--r--gpxe/src/drivers/net/r8169.h566
-rw-r--r--gpxe/src/drivers/net/rtl8139.c3
-rw-r--r--gpxe/src/drivers/net/tg3.c1
-rw-r--r--gpxe/src/drivers/net/via-rhine.c16
-rw-r--r--gpxe/src/drivers/net/virtio-net.c8
-rw-r--r--gpxe/src/drivers/net/w89c840.c4
-rw-r--r--gpxe/src/hci/commands/config_cmd.c2
-rw-r--r--gpxe/src/image/efi_image.c106
-rw-r--r--gpxe/src/include/compiler.h22
-rw-r--r--gpxe/src/include/gpxe/api.h82
-rw-r--r--gpxe/src/include/gpxe/bitops.h227
-rw-r--r--gpxe/src/include/gpxe/efi/Base.h305
-rw-r--r--gpxe/src/include/gpxe/efi/Guid/PcAnsi.h58
-rw-r--r--gpxe/src/include/gpxe/efi/Ia32/ProcessorBind.h221
-rw-r--r--gpxe/src/include/gpxe/efi/IndustryStandard/PeImage.h742
-rw-r--r--gpxe/src/include/gpxe/efi/LICENCE40
-rw-r--r--gpxe/src/include/gpxe/efi/Pi/PiBootMode.h43
-rw-r--r--gpxe/src/include/gpxe/efi/Pi/PiDependency.h47
-rw-r--r--gpxe/src/include/gpxe/efi/Pi/PiDxeCis.h642
-rw-r--r--gpxe/src/include/gpxe/efi/Pi/PiFirmwareFile.h242
-rw-r--r--gpxe/src/include/gpxe/efi/Pi/PiFirmwareVolume.h154
-rw-r--r--gpxe/src/include/gpxe/efi/Pi/PiHob.h293
-rw-r--r--gpxe/src/include/gpxe/efi/Pi/PiMultiPhase.h104
-rw-r--r--gpxe/src/include/gpxe/efi/PiDxe.h25
-rw-r--r--gpxe/src/include/gpxe/efi/ProcessorBind.h10
-rw-r--r--gpxe/src/include/gpxe/efi/Protocol/Cpu.h326
-rw-r--r--gpxe/src/include/gpxe/efi/Protocol/CpuIo.h128
-rw-r--r--gpxe/src/include/gpxe/efi/Protocol/DebugSupport.h656
-rw-r--r--gpxe/src/include/gpxe/efi/Protocol/DevicePath.h560
-rw-r--r--gpxe/src/include/gpxe/efi/Protocol/DriverBinding.h166
-rw-r--r--gpxe/src/include/gpxe/efi/Protocol/PciIo.h577
-rw-r--r--gpxe/src/include/gpxe/efi/Protocol/PciRootBridgeIo.h450
-rw-r--r--gpxe/src/include/gpxe/efi/Protocol/SimpleNetwork.h645
-rw-r--r--gpxe/src/include/gpxe/efi/Protocol/SimpleTextIn.h145
-rw-r--r--gpxe/src/include/gpxe/efi/Protocol/SimpleTextOut.h437
-rw-r--r--gpxe/src/include/gpxe/efi/Uefi.h27
-rw-r--r--gpxe/src/include/gpxe/efi/Uefi/UefiBaseType.h174
-rw-r--r--gpxe/src/include/gpxe/efi/Uefi/UefiGpt.h66
-rw-r--r--gpxe/src/include/gpxe/efi/Uefi/UefiInternalFormRepresentation.h1499
-rw-r--r--gpxe/src/include/gpxe/efi/Uefi/UefiMultiPhase.h218
-rw-r--r--gpxe/src/include/gpxe/efi/Uefi/UefiPxe.h1811
-rw-r--r--gpxe/src/include/gpxe/efi/Uefi/UefiSpec.h1780
-rw-r--r--gpxe/src/include/gpxe/efi/efi.h89
-rw-r--r--gpxe/src/include/gpxe/efi/efi_io.h178
-rw-r--r--gpxe/src/include/gpxe/efi/efi_pci.h146
-rw-r--r--gpxe/src/include/gpxe/efi/efi_timer.h16
-rw-r--r--gpxe/src/include/gpxe/efi/efi_uaccess.h88
-rw-r--r--gpxe/src/include/gpxe/efi/efi_umalloc.h16
-rwxr-xr-xgpxe/src/include/gpxe/efi/import.pl75
-rw-r--r--gpxe/src/include/gpxe/errfile.h7
-rw-r--r--gpxe/src/include/gpxe/ethernet.h2
-rw-r--r--gpxe/src/include/gpxe/features.h1
-rw-r--r--gpxe/src/include/gpxe/i2c.h68
-rw-r--r--gpxe/src/include/gpxe/ib_mad.h364
-rw-r--r--gpxe/src/include/gpxe/ib_packet.h147
-rw-r--r--gpxe/src/include/gpxe/ib_sma.h63
-rw-r--r--gpxe/src/include/gpxe/ib_smc.h18
-rw-r--r--gpxe/src/include/gpxe/infiniband.h519
-rw-r--r--gpxe/src/include/gpxe/init.h1
-rw-r--r--gpxe/src/include/gpxe/io.h504
-rw-r--r--gpxe/src/include/gpxe/iobuf.h18
-rw-r--r--gpxe/src/include/gpxe/ipoib.h47
-rw-r--r--gpxe/src/include/gpxe/nap.h54
-rw-r--r--gpxe/src/include/gpxe/netdevice.h80
-rw-r--r--gpxe/src/include/gpxe/null_nap.h21
-rw-r--r--gpxe/src/include/gpxe/pci.h2
-rw-r--r--gpxe/src/include/gpxe/pci_io.h122
-rw-r--r--gpxe/src/include/gpxe/retry.h9
-rw-r--r--gpxe/src/include/gpxe/rotate.h27
-rw-r--r--gpxe/src/include/gpxe/sanboot.h14
-rw-r--r--gpxe/src/include/gpxe/settings.h15
-rw-r--r--gpxe/src/include/gpxe/timer.h95
-rw-r--r--gpxe/src/include/gpxe/tls.h20
-rw-r--r--gpxe/src/include/gpxe/uaccess.h317
-rw-r--r--gpxe/src/include/gpxe/umalloc.h55
-rw-r--r--gpxe/src/include/gpxe/xfer.h4
-rw-r--r--gpxe/src/include/nic.h1
-rw-r--r--gpxe/src/include/pxe_types.h5
-rw-r--r--gpxe/src/include/stddef.h6
-rw-r--r--gpxe/src/include/stdlib.h1
-rw-r--r--gpxe/src/include/unistd.h18
-rw-r--r--gpxe/src/include/usr/aoeboot.h6
-rw-r--r--gpxe/src/include/usr/iscsiboot.h6
-rw-r--r--gpxe/src/interface/efi/efi_console.c273
-rw-r--r--gpxe/src/interface/efi/efi_entry.c83
-rw-r--r--gpxe/src/interface/efi/efi_io.c201
-rw-r--r--gpxe/src/interface/efi/efi_pci.c81
-rw-r--r--gpxe/src/interface/efi/efi_snp.c980
-rw-r--r--gpxe/src/interface/efi/efi_timer.c115
-rw-r--r--gpxe/src/interface/efi/efi_uaccess.c37
-rw-r--r--gpxe/src/interface/efi/efi_umalloc.c96
-rw-r--r--gpxe/src/interface/pxe/pxe_undi.c30
-rw-r--r--gpxe/src/net/aoe.c15
-rw-r--r--gpxe/src/net/ethernet.c60
-rw-r--r--gpxe/src/net/infiniband.c316
-rw-r--r--gpxe/src/net/ipv4.c15
-rw-r--r--gpxe/src/net/netdevice.c62
-rw-r--r--gpxe/src/net/retry.c12
-rw-r--r--gpxe/src/net/tcp/ftp.c61
-rw-r--r--gpxe/src/net/tls.c37
-rw-r--r--gpxe/src/net/udp/dhcp.c2
-rw-r--r--gpxe/src/net/udp/tftp.c23
-rwxr-xr-x[-rw-r--r--]gpxe/src/tests/gdbstub_test.gdb0
-rw-r--r--gpxe/src/usr/aoeboot.c16
-rw-r--r--gpxe/src/usr/autoboot.c20
-rw-r--r--gpxe/src/usr/ifmgmt.c25
-rw-r--r--gpxe/src/usr/iscsiboot.c16
-rw-r--r--gpxe/src/util/.gitignore1
-rw-r--r--gpxe/src/util/efilink.c507
-rwxr-xr-xgpxe/src/util/geniso2
-rwxr-xr-x[-rw-r--r--]gpxe/src/util/mergerom.pl0
-rwxr-xr-xgpxe/src/util/mkconfig.pl205
-rwxr-xr-xgpxe/src/util/sortobjdump.pl2
-rw-r--r--gpxe/src/util/zbin.c27
255 files changed, 35918 insertions, 8113 deletions
diff --git a/gpxe/Makefile b/gpxe/Makefile
index c846e939..1c06f9eb 100644
--- a/gpxe/Makefile
+++ b/gpxe/Makefile
@@ -32,8 +32,8 @@ spotless: clean dist
installer:
-src/bin/undionly.kpxe: ../core/pxelinux.0
- $(MAKE) -C src EMBEDDED_IMAGE=../$< NO_WERROR=1 bin/undionly.kpxe
+src/bin/undionly.kkpxe: ../core/pxelinux.0
+ $(MAKE) -C src EMBEDDED_IMAGE=../$< NO_WERROR=1 bin/undionly.kkpxe
-gpxelinux.0: src/bin/undionly.kpxe
+gpxelinux.0: src/bin/undionly.kkpxe
cp -f $< $@
diff --git a/gpxe/VERSION b/gpxe/VERSION
index 010605b1..49a7dfae 100644
--- a/gpxe/VERSION
+++ b/gpxe/VERSION
@@ -1 +1 @@
-0.9.5 2008-10-01
+0.9.5+ 2008-10-01
diff --git a/gpxe/src/Makefile b/gpxe/src/Makefile
index 6c42da6a..01048aae 100644
--- a/gpxe/src/Makefile
+++ b/gpxe/src/Makefile
@@ -1,19 +1,17 @@
-# Location to place generated files
+###############################################################################
#
-BIN := bin
-
-# Initialise variables that get added to throughout the various Makefiles
+# Initialise various variables
#
-MAKEDEPS := Makefile .toolcheck .echocheck
-SRCDIRS :=
-SRCS :=
-NON_AUTO_SRCS :=
-DRIVERS :=
-ROMS :=
-MEDIA :=
-NON_AUTO_MEDIA :=
-# Locations of utilities
+CLEANUP :=
+CFLAGS :=
+ASFLAGS :=
+LDFLAGS :=
+MAKEDEPS := Makefile
+
+###############################################################################
+#
+# Locations of tools
#
HOST_CC := gcc
RM := rm -f
@@ -35,109 +33,18 @@ NM := $(CROSS_COMPILE)nm
OBJDUMP := $(CROSS_COMPILE)objdump
PARSEROM := $(PERL) ./util/parserom.pl
MAKEROM := $(PERL) ./util/makerom.pl
-MKCONFIG := $(PERL) ./util/mkconfig.pl
SYMCHECK := $(PERL) ./util/symcheck.pl
SORTOBJDUMP := $(PERL) ./util/sortobjdump.pl
NRV2B := ./util/nrv2b
ZBIN := ./util/zbin
+EFILINK := ./util/efilink
DOXYGEN := doxygen
-# If invoked with no build target, print out a helpfully suggestive
-# message.
-#
-noargs : blib $(BIN)/NIC $(BIN)/gpxe.dsk $(BIN)/gpxe.iso $(BIN)/gpxe.usb $(BIN)/undionly.kpxe
- @$(ECHO) '==========================================================='
- @$(ECHO)
- @$(ECHO) 'To create a bootable floppy, type'
- @$(ECHO) ' cat $(BIN)/gpxe.dsk > /dev/fd0'
- @$(ECHO) 'where /dev/fd0 is your floppy drive. This will erase any'
- @$(ECHO) 'data already on the disk.'
- @$(ECHO)
- @$(ECHO) 'To create a bootable USB key, type'
- @$(ECHO) ' cat $(BIN)/gpxe.usb > /dev/sdX'
- @$(ECHO) 'where /dev/sdX is your USB key, and is *not* a real hard'
- @$(ECHO) 'disk on your system. This will erase any data already on'
- @$(ECHO) 'the USB key.'
- @$(ECHO)
- @$(ECHO) 'To create a bootable CD-ROM, burn the ISO image '
- @$(ECHO) '$(BIN)/gpxe.iso to a blank CD-ROM.'
- @$(ECHO)
- @$(ECHO) 'These images contain drivers for all supported cards. You'
- @$(ECHO) 'can build more customised images, and ROM images, using'
- @$(ECHO) ' make bin/<rom-name>.<output-format>'
- @$(ECHO)
- @$(ECHO) '==========================================================='
-
-# If no architecture is specified in Config or on the command-line,
-# use that of the build machine.
-#
-ARCH := $(shell uname -m | sed -e 's,i[3456789]86,i386,')
-
-# handle x86_64 like i386, but set -m32 option for 32bit code only
-ifeq ($(ARCH),x86_64)
-ARCH := i386
-CFLAGS += -m32
-ASFLAGS += --32
-LDFLAGS += -m elf_i386
-endif
-
-# Drag in architecture-specific Config
-#
-MAKEDEPS += arch/$(ARCH)/Config
-include arch/$(ARCH)/Config
-
-# Common flags
-#
-CFLAGS += -I include -I arch/$(ARCH)/include -I . -DARCH=$(ARCH)
-CFLAGS += -Os -ffreestanding
-CFLAGS += -Wall -W
-CFLAGS += -g
-CFLAGS += $(EXTRA_CFLAGS)
-ASFLAGS += $(EXTRA_ASFLAGS)
-LDFLAGS += $(EXTRA_LDFLAGS)
-
-# Embedded image, if present
+###############################################################################
#
-EMBEDDED_IMAGE = /dev/null
-
-ifneq ($(NO_WERROR),1)
-CFLAGS += -Werror
-endif
-
-# CFLAGS for specific object types
-#
-CFLAGS_c +=
-CFLAGS_S += -DASSEMBLY
-
-# Base object name of the current target
-#
-OBJECT = $(firstword $(subst ., ,$(@F)))
-
-# CFLAGS for specific object files. You can define
-# e.g. CFLAGS_rtl8139, and have those flags automatically used when
-# compiling bin/rtl8139.o.
-#
-OBJ_CFLAGS = $(CFLAGS_$(OBJECT)) -DOBJECT=$(subst -,_,$(OBJECT))
-$(BIN)/%.flags :
- @$(ECHO) $(OBJ_CFLAGS)
-
-# Rules for specific object types.
-#
-COMPILE_c = $(CC) $(CFLAGS) $(CFLAGS_c) $(OBJ_CFLAGS)
-RULE_c = $(Q)$(COMPILE_c) -c $< -o $@
-RULE_c_to_dbg%.o = $(Q)$(COMPILE_c) -Ddebug_$(OBJECT)=$* -c $< -o $@
-RULE_c_to_c = $(Q)$(COMPILE_c) -E -c $< > $@
-RULE_c_to_s = $(Q)$(COMPILE_c) -S -g0 -c $< -o $@
-
-PREPROCESS_S = $(CPP) $(CFLAGS) $(CFLAGS_S) $(OBJ_CFLAGS)
-ASSEMBLE_S = $(AS) $(ASFLAGS)
-RULE_S = $(Q)$(PREPROCESS_S) $< | $(ASSEMBLE_S) -o $@
-RULE_S_to_s = $(Q)$(PREPROCESS_S) $< > $@
-
-DEBUG_TARGETS += dbg%.o c s
-
# SRCDIRS lists all directories containing source files.
#
+SRCDIRS :=
SRCDIRS += libgcc
SRCDIRS += core
SRCDIRS += proto
@@ -151,7 +58,7 @@ SRCDIRS += drivers/block
SRCDIRS += drivers/nvs
SRCDIRS += drivers/bitbash
SRCDIRS += drivers/infiniband
-SRCDIRS += interface/pxe
+SRCDIRS += interface/pxe interface/efi
SRCDIRS += tests
SRCDIRS += crypto crypto/axtls crypto/matrixssl
SRCDIRS += hci hci/commands hci/tui
@@ -161,25 +68,68 @@ SRCDIRS += usr
# NON_AUTO_SRCS lists files that are excluded from the normal
# automatic build system.
#
-NON_AUTO_SRCS += core/elf_loader.c
+NON_AUTO_SRCS :=
NON_AUTO_SRCS += drivers/net/prism2.c
-# Rules for finalising files. TGT_MAKEROM_FLAGS is defined as part of
-# the automatic build system and varies by target; it includes the
-# "-p 0x1234,0x5678" string to set the PCI IDs.
+###############################################################################
+#
+# Default build target: build the most common targets and print out a
+# helpfully suggestive message
#
-FINALISE_rom = $(MAKEROM) $(MAKEROM_FLAGS) $(TGT_MAKEROM_FLAGS) \
- -i$(IDENT) -s 0 $@
+all : bin/blib.a bin/gpxe.dsk bin/gpxe.iso bin/gpxe.usb bin/undionly.kpxe
+ @$(ECHO) '==========================================================='
+ @$(ECHO)
+ @$(ECHO) 'To create a bootable floppy, type'
+ @$(ECHO) ' cat bin/gpxe.dsk > /dev/fd0'
+ @$(ECHO) 'where /dev/fd0 is your floppy drive. This will erase any'
+ @$(ECHO) 'data already on the disk.'
+ @$(ECHO)
+ @$(ECHO) 'To create a bootable USB key, type'
+ @$(ECHO) ' cat bin/gpxe.usb > /dev/sdX'
+ @$(ECHO) 'where /dev/sdX is your USB key, and is *not* a real hard'
+ @$(ECHO) 'disk on your system. This will erase any data already on'
+ @$(ECHO) 'the USB key.'
+ @$(ECHO)
+ @$(ECHO) 'To create a bootable CD-ROM, burn the ISO image '
+ @$(ECHO) 'bin/gpxe.iso to a blank CD-ROM.'
+ @$(ECHO)
+ @$(ECHO) 'These images contain drivers for all supported cards. You'
+ @$(ECHO) 'can build more customised images, and ROM images, using'
+ @$(ECHO) ' make bin/<rom-name>.<output-format>'
+ @$(ECHO)
+ @$(ECHO) '==========================================================='
+
+###############################################################################
+#
+# Build targets that do nothing but might be tried by users
+#
+configure :
+ @$(ECHO) "No configuration needed."
+
+install :
+ @$(ECHO) "No installation required."
-# Some ROMs require specific flags to be passed to makerom.pl
+###############################################################################
#
-MAKEROM_FLAGS_3c503 = -3
+# Version number calculations
+#
+VERSION_MAJOR = 0
+VERSION_MINOR = 9
+VERSION_PATCH = 5
+EXTRAVERSION = +
+MM_VERSION = $(VERSION_MAJOR).$(VERSION_MINOR)
+VERSION = $(MM_VERSION).$(VERSION_PATCH)$(EXTRAVERSION)
+CFLAGS += -DVERSION_MAJOR=$(VERSION_MAJOR) \
+ -DVERSION_MINOR=$(VERSION_MINOR) \
+ -DVERSION=\"$(VERSION)\"
+IDENT = '$(@F) $(VERSION) (GPL) etherboot.org'
+version :
+ @$(ECHO) $(VERSION)
-# Drag in architecture-specific Makefile
+###############################################################################
+#
+# Drag in the bulk of the build system
#
-MAKEDEPS += arch/$(ARCH)/Makefile
-include arch/$(ARCH)/Makefile
-# Drag in the automatic build system and other housekeeping functions
MAKEDEPS += Makefile.housekeeping
include Makefile.housekeeping
diff --git a/gpxe/src/Makefile.housekeeping b/gpxe/src/Makefile.housekeeping
index 9e11ceb4..067ac826 100644
--- a/gpxe/src/Makefile.housekeeping
+++ b/gpxe/src/Makefile.housekeeping
@@ -1,50 +1,10 @@
# -*- makefile -*- : Force emacs to use Makefile mode
-
+#
# This file contains various boring housekeeping functions that would
# otherwise seriously clutter up the main Makefile.
-# Objects to be removed by "make clean"
-#
-CLEANUP := $(BIN)/*.* # *.* to avoid catching the "CVS" directory
-
-# Version number calculations
-#
-VERSION_MAJOR = 0
-VERSION_MINOR = 9
-VERSION_PATCH = 5
-EXTRAVERSION =
-MM_VERSION = $(VERSION_MAJOR).$(VERSION_MINOR)
-VERSION = $(MM_VERSION).$(VERSION_PATCH)$(EXTRAVERSION)
-CFLAGS += -DVERSION_MAJOR=$(VERSION_MAJOR) \
- -DVERSION_MINOR=$(VERSION_MINOR) \
- -DVERSION=\"$(VERSION)\"
-IDENT = '$(@F) $(VERSION) (GPL) etherboot.org'
-version :
- @$(ECHO) $(VERSION)
-
-configure :
- @$(ECHO) "No configuration needed."
-
-install :
- @$(ECHO) "No installation required. Generated images will be placed in the" $(BIN) "directory."
-
-# Check for tools that can cause failed builds
+###############################################################################
#
-.toolcheck : Makefile
- @if $(CC) -v 2>&1 | grep -is 'gcc version 2\.96' > /dev/null; then \
- $(ECHO) 'gcc 2.96 is unsuitable for compiling Etherboot'; \
- $(ECHO) 'Use gcc 2.95 or gcc 3.x instead'; \
- exit 1; \
- fi
- @if [ `perl -e 'use bytes; print chr(255)' | wc -c` = 2 ]; then \
- $(ECHO) 'Your Perl version has a Unicode handling bug'; \
- $(ECHO) 'Execute this command before compiling Etherboot:'; \
- $(ECHO) 'export LANG=$${LANG%.UTF-8}'; \
- exit 1; \
- fi
- @$(TOUCH) $@
-VERYCLEANUP += .toolcheck
-
# Find a usable "echo -e" substitute.
#
TAB := $(shell $(PRINTF) '\t')
@@ -86,20 +46,44 @@ else
@$(ECHO) "No usable \"echo -e\" substitute found"
@exit 1
endif
+MAKEDEPS += .echocheck
VERYCLEANUP += .echocheck
echo :
@$(ECHO) "Using \"$(ECHO_E)\" for \"echo -e\""
-# Build verbosity
+###############################################################################
+#
+# Determine host OS
+#
+HOST_OS := $(shell uname -s)
+hostos :
+ @$(ECHO) $(HOST_OS)
+
+###############################################################################
+#
+# Check for tools that can cause failed builds
+#
+.toolcheck :
+ @if $(CC) -v 2>&1 | grep -is 'gcc version 2\.96' > /dev/null; then \
+ $(ECHO) 'gcc 2.96 is unsuitable for compiling Etherboot'; \
+ $(ECHO) 'Use gcc 2.95 or gcc 3.x instead'; \
+ exit 1; \
+ fi
+ @if [ `perl -e 'use bytes; print chr(255)' | wc -c` = 2 ]; then \
+ $(ECHO) 'Your Perl version has a Unicode handling bug'; \
+ $(ECHO) 'Execute this command before compiling Etherboot:'; \
+ $(ECHO) 'export LANG=$${LANG%.UTF-8}'; \
+ exit 1; \
+ fi
+ @$(TOUCH) $@
+MAKEDEPS += .toolcheck
+VERYCLEANUP += .toolcheck
+
+###############################################################################
+#
+# Check for various tool workarounds
#
-ifeq ($(V),1)
-Q =
-QM = @\#
-else
-Q = @
-QM = @
-endif
# Check for an old version of gas (binutils 2.9.1)
#
@@ -112,18 +96,154 @@ oldgas :
# default, even when -ffreestanding is specified. We therefore need
# to disable -fstack-protector if the compiler supports it.
#
-SP_TEST = $(CC) -fno-stack-protector -x c -E - < /dev/null >/dev/null 2>&1
+SP_TEST = $(CC) -fno-stack-protector -x c -c /dev/null \
+ -o /dev/null >/dev/null 2>&1
SP_FLAGS := $(shell $(SP_TEST) && $(ECHO) '-fno-stack-protector')
CFLAGS += $(SP_FLAGS)
-# compiler.h is needed for our linking and debugging system
+###############################################################################
+#
+# Build verbosity
+#
+ifeq ($(V),1)
+Q :=
+QM := @\#
+else
+Q := @
+QM := @
+endif
+
+###############################################################################
+#
+# Set BIN according to whatever was specified on the command line as
+# the build target.
+#
+
+# Determine how many different BIN directories are mentioned in the
+# make goals.
+#
+BIN_GOALS := $(filter bin/% bin-%,$(MAKECMDGOALS))
+BIN_GOAL_BINS := $(foreach BG,$(BIN_GOALS),$(firstword $(subst /, ,$(BG))))
+NUM_BINS := $(words $(sort $(BIN_GOAL_BINS)))
+
+ifeq ($(NUM_BINS),0)
+
+# No BIN directory was specified. Set BIN to "bin" as a sensible
+# default.
+
+BIN := bin
+
+else # NUM_BINS == 0
+
+ifeq ($(NUM_BINS),1)
+
+# If exactly one BIN directory was specified, set BIN to match this
+# directory.
+#
+BIN := $(firstword $(BIN_GOAL_BINS))
+
+else # NUM_BINS == 1
+
+# More than one BIN directory was specified. We cannot handle the
+# latter case within a single make invocation, so set up recursive
+# targets for each BIN directory.
+#
+# Leave $(BIN) undefined. This has implications for any target that
+# depends on $(BIN); such targets should be made conditional upon the
+# existence of $(BIN).
+#
+$(BIN_GOALS) : % : BIN_RECURSE
+ $(Q)$(MAKE) --no-print-directory BIN=$(firstword $(subst /, ,$@)) $@
+.PHONY : BIN_RECURSE
+
+endif # NUM_BINS == 1
+endif # NUM_BINS == 0
+
+ifdef BIN
+
+# Create $(BIN) directory if it doesn't exist yet
+#
+ifeq ($(wildcard $(BIN)),)
+$(shell $(MKDIR) -p $(BIN))
+endif
+
+# Target to allow e.g. "make bin-efi arch"
+#
+$(BIN) :
+ @# Do nothing, silently
+.PHONY : $(BIN)
+
+# Remove everything in $(BIN) for a "make clean"
+#
+CLEANUP += $(BIN)/*.* # Avoid picking up directories
+
+endif # defined(BIN)
+
+# Determine whether or not we need to include the dependency files
#
-CFLAGS += -include compiler.h
+NO_DEP_TARGETS := $(BIN) clean veryclean
+ifeq ($(MAKECMDGOALS),)
+NEED_DEPS := 1
+endif
+ifneq ($(strip $(filter-out $(NO_DEP_TARGETS),$(MAKECMDGOALS))),)
+NEED_DEPS := 1
+endif
-# config/%.h files are generated from config.h using mkconfig.pl
-config/%.h : config*.h
- $(MKCONFIG) config.h
-CLEANUP += config/*.h
+###############################################################################
+#
+# Select build architecture and platform based on $(BIN)
+#
+# BIN has the form bin[-[arch-]platform]
+
+ARCHS := $(patsubst arch/%,%,$(wildcard arch/*))
+PLATFORMS := $(patsubst config/defaults/%.h,%,\
+ $(wildcard config/defaults/*.h))
+archs :
+ @$(ECHO) $(ARCHS)
+
+platforms :
+ @$(ECHO) $(PLATFORMS)
+
+ifdef BIN
+
+# Determine architecture portion of $(BIN), if present
+BIN_ARCH := $(strip $(foreach A,$(ARCHS),\
+ $(patsubst bin-$(A)-%,$(A),\
+ $(filter bin-$(A)-%,$(BIN)))))
+
+# Determine platform portion of $(BIN), if present
+ifeq ($(BIN_ARCH),)
+BIN_PLATFORM := $(patsubst bin-%,%,$(filter bin-%,$(BIN)))
+else
+BIN_PLATFORM := $(patsubst bin-$(BIN_ARCH)-%,%,$(BIN))
+endif
+
+# Determine build architecture
+DEFAULT_ARCH := i386
+ARCH := $(firstword $(BIN_ARCH) $(DEFAULT_ARCH))
+CFLAGS += -DARCH=$(ARCH)
+arch :
+ @$(ECHO) $(ARCH)
+.PHONY : arch
+
+# Determine build platform
+DEFAULT_PLATFORM := pcbios
+PLATFORM := $(firstword $(BIN_PLATFORM) $(DEFAULT_PLATFORM))
+CFLAGS += -DPLATFORM=$(PLATFORM)
+platform :
+ @$(ECHO) $(PLATFORM)
+
+endif # defined(BIN)
+
+# Include architecture-specific Makefile
+ifdef ARCH
+MAKEDEPS += arch/$(ARCH)/Makefile
+include arch/$(ARCH)/Makefile
+endif
+
+###############################################################################
+#
+# Source file handling
# SRCDIRS lists all directories containing source files.
srcdirs :
@@ -144,6 +264,67 @@ AUTO_SRCS = $(filter-out $(NON_AUTO_SRCS),$(SRCS))
autosrcs :
@$(ECHO) $(AUTO_SRCS)
+# Just about everything else in this section depends upon having
+# $(BIN) set
+
+ifdef BIN
+
+# Common flags
+#
+CFLAGS += -I include -I arch/$(ARCH)/include -I .
+CFLAGS += -Os -ffreestanding
+CFLAGS += -Wall -W -Wformat-nonliteral
+CFLAGS += -g
+CFLAGS += $(EXTRA_CFLAGS)
+ASFLAGS += $(EXTRA_ASFLAGS)
+LDFLAGS += $(EXTRA_LDFLAGS)
+
+# Embedded image, if present
+#
+EMBEDDED_IMAGE = /dev/null
+
+# Inhibit -Werror if NO_WERROR is specified on make command line
+#
+ifneq ($(NO_WERROR),1)
+CFLAGS += -Werror
+endif
+
+# compiler.h is needed for our linking and debugging system
+#
+CFLAGS += -include compiler.h
+
+# CFLAGS for specific object types
+#
+CFLAGS_c +=
+CFLAGS_S += -DASSEMBLY
+
+# Base object name of the current target
+#
+OBJECT = $(firstword $(subst ., ,$(@F)))
+
+# CFLAGS for specific object files. You can define
+# e.g. CFLAGS_rtl8139, and have those flags automatically used when
+# compiling bin/rtl8139.o.
+#
+OBJ_CFLAGS = $(CFLAGS_$(OBJECT)) -DOBJECT=$(subst -,_,$(OBJECT))
+$(BIN)/%.flags :
+ @$(ECHO) $(OBJ_CFLAGS)
+
+# Rules for specific object types.
+#
+COMPILE_c = $(CC) $(CFLAGS) $(CFLAGS_c) $(OBJ_CFLAGS)
+RULE_c = $(Q)$(COMPILE_c) -c $< -o $@
+RULE_c_to_dbg%.o = $(Q)$(COMPILE_c) -Ddebug_$(OBJECT)=$* -c $< -o $@
+RULE_c_to_c = $(Q)$(COMPILE_c) -E -c $< > $@
+RULE_c_to_s = $(Q)$(COMPILE_c) -S -g0 -c $< -o $@
+
+PREPROCESS_S = $(CPP) $(CFLAGS) $(CFLAGS_S) $(OBJ_CFLAGS)
+ASSEMBLE_S = $(AS) $(ASFLAGS)
+RULE_S = $(Q)$(PREPROCESS_S) $< | $(ASSEMBLE_S) -o $@
+RULE_S_to_s = $(Q)$(PREPROCESS_S) $< > $@
+
+DEBUG_TARGETS += dbg%.o c s
+
# We automatically generate rules for any file mentioned in AUTO_SRCS
# using the following set of templates. It would be cleaner to use
# $(eval ...), but this function exists only in GNU make >= 3.80.
@@ -157,7 +338,7 @@ autosrcs :
#
define src_template
- @$(ECHO) "Generating Makefile rules for $(1)"
+ @$(ECHO) " [DEPS] $(1)"
@$(MKDIR) -p $(dir $(2))
@$(RM) $(2)
@$(TOUCH) $(2)
@@ -182,13 +363,13 @@ define obj_template
-Wno-error -MM $(1) -MT "$(4)_DEPS" -MG -MP | \
sed 's/_DEPS\s*:/_DEPS =/' >> $(2)
@$(ECHO_E) '\n$$(BIN)/$(4).o : $(1) $$(MAKEDEPS) $$($(4)_DEPS)' \
- '\n\t$$(QM)$(ECHO) " [BUILD] $$@"\n' \
+ '\n\t$$(QM)$(ECHO) " [BUILD] $$@"' \
'\n\t$$(RULE_$(3))\n' \
'\nBOBJS += $$(BIN)/$(4).o\n' \
$(foreach TGT,$(DEBUG_TARGETS), \
$(if $(RULE_$(3)_to_$(TGT)), \
'\n$$(BIN)/$(4).$(TGT) : $(1) $$(MAKEDEPS) $$($(4)_DEPS)' \
- '\n\t$$(QM)$(ECHO) " [BUILD] $$@"\n' \
+ '\n\t$$(QM)$(ECHO) " [BUILD] $$@"' \
'\n\t$$(RULE_$(3)_to_$(TGT))\n' \
'\n$(TGT)_OBJS += $$(BIN)/$(4).$(TGT)\n' ) ) \
'\n$(2) : $$($(4)_DEPS)\n' \
@@ -205,7 +386,11 @@ $(BIN)/deps/%.d : % $(MAKEDEPS) $(PARSEROM)
# Calculate and include the list of Makefile rules files
#
AUTO_DEPS = $(patsubst %,$(BIN)/deps/%.d,$(AUTO_SRCS))
+ifdef NEED_DEPS
+ifneq ($(AUTO_DEPS),)
-include $(AUTO_DEPS)
+endif
+endif
autodeps :
@$(ECHO) $(AUTO_DEPS)
VERYCLEANUP += $(BIN)/deps
@@ -237,7 +422,7 @@ $(BIN)/NIC : $(AUTO_DEPS)
'it is only for rom-o-matic' >> $@
@$(ECHO) >> $@
@perl -ne 'chomp; print "$$1\n" if /\# NIC\t(.*)$$/' $^ >> $@
-CLEANUP += $(BIN)/NIC
+CLEANUP += $(BIN)/NIC # Doesn't match the $(BIN)/*.* pattern
# Analyse a target name (e.g. "bin/dfe538--prism2_pci.zrom.tmp") and
# derive the variables:
@@ -342,8 +527,13 @@ $(BIN)/%.info :
# in order to correctly rebuild blib whenever the list of objects
# changes.
#
-BLIB_LIST = $(BIN)/.blib.list
-ifneq ($(shell cat $(BLIB_LIST)),$(BLIB_OBJS))
+BLIB_LIST := $(BIN)/.blib.list
+ifeq ($(wildcard $(BLIB_LIST)),)
+BLIB_LIST_OBJS :=
+else
+BLIB_LIST_OBJS := $(shell cat $(BLIB_LIST))
+endif
+ifneq ($(BLIB_LIST_OBJS),$(BLIB_OBJS))
$(shell $(ECHO) "$(BLIB_OBJS)" > $(BLIB_LIST))
endif
@@ -396,10 +586,6 @@ $(BIN)/%.zbin : $(BIN)/%.bin $(BIN)/%.zinfo $(ZBIN)
$(QM)$(ECHO) " [ZBIN] $@"
$(Q)$(ZBIN) $(BIN)/$*.bin $(BIN)/$*.zinfo > $@
-# Build bochs symbol table
-$(BIN)/%.bxs : $(BIN)/%.tmp
- $(NM) $< | cut -d" " -f1,3 > $@
-
# Rules for each media format. These are generated and placed in an
# external Makefile fragment. We could do this via $(eval ...), but
# that would require make >= 3.80.
@@ -435,7 +621,7 @@ automedia :
#
define media_template
- @$(ECHO) "Generating Makefile rules for $(1) media"
+ @$(ECHO) " [MEDIADEPS] $(1)"
@$(MKDIR) -p $(dir $(2))
@$(RM) $(2)
@$(TOUCH) $(2)
@@ -459,7 +645,20 @@ $(BIN)/deps/%.media.d : $(MAKEDEPS)
MEDIA_DEPS = $(patsubst %,$(BIN)/deps/%.media.d,$(AUTO_MEDIA))
mediadeps :
@$(ECHO) $(MEDIA_DEPS)
+ifdef NEED_DEPS
+ifneq ($(MEDIA_DEPS),)
-include $(MEDIA_DEPS)
+endif
+endif
+
+# Wrap up binary blobs (for embedded images)
+#
+$(BIN)/%.o : payload/%.img
+ $(QM)echo " [WRAP] $@"
+ $(Q)$(LD) -b binary -r -o $@ $< --undefined obj_payload \
+ --defsym obj_$*=0
+
+BOBJS += $(patsubst payload/%.img,$(BIN)/%.o,$(wildcard payload/*.img))
# The "allXXXs" targets for each suffix
#
@@ -472,15 +671,23 @@ allpxes allisos alldsks : all%s : $(foreach DRIVER,$(DRIVERS),$(BIN)/$(DRIVER).%
$(BIN)/etherboot.% : $(BIN)/gpxe.%
ln -sf $(notdir $<) $@
-# Wrap up binary blobs
+endif # defined(BIN)
+
+###############################################################################
#
-$(BIN)/%.o : payload/%.img
- $(QM)echo " [WRAP] $@"
- $(Q)$(LD) -b binary -r -o $@ $< --undefined obj_payload \
- --defsym obj_$*=0
+# Rules for finalising files. TGT_MAKEROM_FLAGS is defined as part of
+# the automatic build system and varies by target; it includes the
+# "-p 0x1234,0x5678" string to set the PCI IDs.
+#
+FINALISE_rom = $(MAKEROM) $(MAKEROM_FLAGS) $(TGT_MAKEROM_FLAGS) \
+ -i$(IDENT) -s 0 $@
-BOBJS += $(patsubst payload/%.img,$(BIN)/%.o,$(wildcard payload/*.img))
+# Some ROMs require specific flags to be passed to makerom.pl
+#
+MAKEROM_FLAGS_3c503 = -3
+###############################################################################
+#
# The compression utilities
#
$(NRV2B) : util/nrv2b.c $(MAKEDEPS)
@@ -494,6 +701,17 @@ $(ZBIN) : util/zbin.c util/nrv2b.c $(MAKEDEPS)
$(Q)$(HOST_CC) -O2 -o $@ $<
CLEANUP += $(ZBIN)
+###############################################################################
+#
+# The EFI custom linker
+#
+$(EFILINK) : util/efilink.c $(MAKEDEPS)
+ $(QM)$(ECHO) " [HOSTCC] $@"
+ $(Q)$(HOST_CC) -O2 -o $@ $< -lbfd
+CLEANUP += $(EFILINK)
+
+###############################################################################
+#
# Auto-incrementing build serial number. Append "bs" to your list of
# build targets to get a serial number printed at the end of the
# build. Enable -DBUILD_SERIAL in order to see it when the code runs.
@@ -517,27 +735,30 @@ bs : $(BUILDSERIAL_NOW)
@$(ECHO) $$(( $(shell cat $<) + 1 )) > $(BUILDSERIAL_NEXT)
@$(ECHO) "Build serial number is $(shell cat $<)"
-# List of available architectures
+###############################################################################
#
-ARCHS = $(filter-out CVS,$(patsubst arch/%,%,$(wildcard arch/*)))
-archs :
- @$(ECHO) $(ARCHS)
+# Build the TAGS file(s) for emacs
+#
+TAGS :
+ ctags -e -R -f $@ --exclude=bin
-OTHER_ARCHS = $(filter-out $(ARCH),$(ARCHS))
-otherarchs :
- @$(ECHO) $(OTHER_ARCHS)
+CLEANUP += TAGS
-# Build the TAGS file for emacs
+###############################################################################
#
-TAGS : TAGS.$(ARCH)
-
-TAGS.$(ARCH) :
- ctags -e -R -f $@ --exclude=bin \
- $(foreach ARCH,$(OTHER_ARCHS),--exclude=arch/$(ARCH))
-CLEANUP += TAGS*
+# Force rebuild for any given target
+#
+%.rebuild :
+ rm -f $*
+ $(Q)$(MAKE) $*
+###############################################################################
+#
# Symbol table checks
#
+
+ifdef BIN
+
SYMTAB = $(BIN)/symtab
$(SYMTAB) : $(BLIB)
$(OBJDUMP) -w -t $< > $@
@@ -547,14 +768,27 @@ CLEANUP += $(BIN)/symtab
symcheck : $(SYMTAB)
$(SYMCHECK) $<
-# Force rebuild for any given target
+endif # defined(BIN)
+
+###############################################################################
+#
+# Build bochs symbol table
#
-$(BIN)/%.rebuild :
- rm -f $(BIN)/$*
- $(MAKE) $(MAKEFLAGS) $(BIN)/$*
+ifdef BIN
+
+$(BIN)/%.bxs : $(BIN)/%.tmp
+ $(NM) $< | cut -d" " -f1,3 > $@
+
+endif # defined(BIN)
+
+###############################################################################
+#
# Documentation
#
+
+ifdef BIN
+
$(BIN)/doxygen.cfg : doxygen.cfg $(MAKEDEPS)
$(PERL) -pe 's{\@SRCDIRS\@}{$(SRCDIRS)}; ' \
-e 's{\@BIN\@}{$(BIN)}; ' \
@@ -578,6 +812,10 @@ docview :
$(ECHO) "Documentation index in $(BIN)/doc/html/index.html" ; \
fi
+endif # defined(BIN)
+
+###############################################################################
+#
# Clean-up
#
clean :
@@ -585,19 +823,3 @@ clean :
veryclean : clean
$(RM) -r $(VERYCLEANUP)
-
-# Make clean tarballs for release
-
-tarball : ../VERSION
- ($(ECHO) -n $(VERSION) ''; date -u +'%Y-%m-%d') > ../VERSION
- $(RM) -r /tmp/$(USER)/gpxe-$(VERSION)
- mkdir -p /tmp/$(USER)/gpxe-$(VERSION)
- cp -rP .. /tmp/$(USER)/gpxe-$(VERSION)
- ( cd /tmp/$(USER)/gpxe-$(VERSION)/src ; $(MAKE) veryclean ; $(RM) -r bin/deps )
- ( cd /tmp/$(USER); tar cf /tmp/$(USER)/gpxe-$(VERSION).tar --exclude ".git*" --exclude "#*" \
- --exclude "*~" gpxe-$(VERSION) )
- bzip2 -9 < /tmp/$(USER)/gpxe-$(VERSION).tar > /tmp/$(USER)/gpxe-$(VERSION).tar.bz2
- gzip -9 < /tmp/$(USER)/gpxe-$(VERSION).tar > /tmp/$(USER)/gpxe-$(VERSION).tar.gz
- $(RM) -r /tmp/$(USER)/gpxe-$(VERSION)
- $(RM) /tmp/$(USER)/gpxe-$(VERSION).tar
- ( cd /tmp/$(USER) ; tar -zxf /tmp/$(USER)/gpxe-$(VERSION).tar.gz )
diff --git a/gpxe/src/arch/i386/Config b/gpxe/src/arch/i386/Config
deleted file mode 100644
index 1c086ecc..00000000
--- a/gpxe/src/arch/i386/Config
+++ /dev/null
@@ -1,148 +0,0 @@
-# -*- makefile -*-
-
-##############################################################################
-##############################################################################
-#
-# IMPORTANT!
-#
-# The use of this file to set options that affect only single object
-# files is deprecated, because changing anything in this file results
-# in a complete rebuild, which is slow. All options are gradually
-# being migrated to config.h, which does not suffer from this problem.
-#
-# Only options that affect the entire build (e.g. overriding the $(CC)
-# Makefile variable) should be placed in here.
-#
-##############################################################################
-##############################################################################
-
-
-# Config for i386 Etherboot
-#
-# Do not delete the tag OptionDescription and /OptionDescription
-# It is used to automatically generate the documentation.
-#
-# @OptionDescrition@
-#
-# BIOS interface options:
-#
-# -DPCBIOS
-# Compile in support for the normal pcbios
-# -DLINUXBIOS
-# Compile in support for LinuxBIOS
-# -DBBS_BUT_NOT_PNP_COMPLIANT
-# Some BIOSes claim to be PNP but they don't conform
-# to the BBS spec which specifies that ES:DI must
-# point to the string $PnP on entry. This option
-# works around those. This option must be added to
-# LCONFIG.
-# -DNO_DELAYED_INT
-# Take control as soon as BIOS detects the ROM.
-# Normally hooks onto INT18H or INT19H. Use only if you
-# have a very non-conformant BIOS as it bypasses
-# BIOS initialisation of devices. This only works for
-# legacy ROMs, i.e. PCI_PNP_HEADER not defined.
-# This option was formerly called NOINT19H.
-# -DBOOT_INT18H
-# Etherboot normally hooks onto INT19H for legacy ROMs.
-# You can choose to hook onto INT18H (BASIC interpreter
-# entry point) instead. This entry point is used when
-# all boot devices have been exhausted. This option must
-# be added to LCONFIG.
-# -DCONFIG_PCI_DIRECT
-# Define this for PCI BIOSes that do not implement
-# BIOS32 or not correctly. Normally not needed.
-# Only works for BIOSes of a certain era.
-# -DCONFIG_TSC_CURRTICKS
-# Uses the processor time stamp counter instead of reading
-# the BIOS time counter. This allows Etherboot to work
-# even without a BIOS. This only works on late model
-# 486s and above.
-# -DCONFIG_NO_TIMER2
-# Some systems do not have timer2 implemented.
-# If you have a RTC this will allow you to roughly calibrate
-# it using outb instructions.
-#
-# Extended cpu options
-
-# -DCONFIG_X86_64
-# Compile in support for booting x86_64 64bit binaries.
-#
-# PXE loader options:
-#
-# -DPXELOADER_KEEP_ALL
-# Prevent PXE loader (prefix) from unloading the
-# PXE stack. You will want to use this if, for
-# example, you are booting via PXE-on-floppy.
-# You may want to use it under certain
-# circumstances when using the Etherboot UNDI
-# driver; these are complex and best practice is
-# not yet established.
-#
-# Obscure options you probably don't need to touch:
-#
-# -DIGNORE_E820_MAP
-# Ignore the memory map returned by the E820 BIOS
-# call. May be necessary on some buggy BIOSes.
-# -DT503_AUI
-# Use AUI by default on 3c503 cards.
-# -DFLATTEN_REAL_MODE
-# Use 4GB segment limits when calling out to or
-# returning to real-mode code. This is necessary to
-# work around some buggy code (e.g. OpenBSD's pxeboot)
-# that uses flat real-mode without being sufficiently
-# paranoid about the volatility of its segment limits.
-
-#
-# @/OptionDescription@
-
-# BIOS select don't change unless you know what you are doing
-# CFLAGS+= -DPCBIOS
-
-# Compile in k8/hammer support
-# CFLAGS+= -DCONFIG_X86_64
-
-# Options to make a version of Etherboot that will work under linuxBIOS.
-# CFLAGS+= -DLINUXBIOS -DCONFIG_TSC_CURRTICKS -DCONSOLE_SERIAL -DCOMCONSOLE=0x3f8 -DCOMPRESERVE -DCONFIG_PCI_DIRECT -DELF_IMAGE
-
-# These options affect the loader that is prepended to the Etherboot image
-# LCONFIG+= -DBBS_BUT_NOT_PNP_COMPLIANT
-# LCONFIG+= -DBOOT_INT18H
-
-# Produce code that will work with OpenBSD's pxeboot
-# CFLAGS+= -DFLATTEN_REAL_MODE
-
-CFLAGS+= -fstrength-reduce -fomit-frame-pointer -march=i386
-# Squeeze the code in as little space as possible.
-# gcc3 needs a different syntax to gcc2 if you want to avoid spurious warnings.
-GCC_VERSION = $(subst ., ,$(shell $(CC) -dumpversion))
-GCC_MAJORVERSION = $(firstword $(GCC_VERSION))
-ifeq ($(GCC_MAJORVERSION),2)
-CFLAGS+= -malign-jumps=1 -malign-loops=1 -malign-functions=1
-else
-CFLAGS+= -falign-jumps=1 -falign-loops=1 -falign-functions=1
-endif
-
-# this is almost always a win. the kernel uses it, too.
-CFLAGS+= -mpreferred-stack-boundary=2
-
-# use regparm for all functions - C functions called from assembly (or
-# vice versa) need __cdecl now
-CFLAGS+= -mregparm=3
-
-# use -mrtd (same __cdecl requirements as above)
-CFLAGS+= -mrtd
-
-# this is the logical complement to -mregparm=3.
-# it doesn't currently buy us anything, but if anything ever tries
-# to return small structures, let's be prepared
-CFLAGS+= -freg-struct-return
-
-LDFLAGS+= -N --no-check-sections
-
-ifeq "$(shell uname -s)" "FreeBSD"
-CFLAGS+= -DIMAGE_FREEBSD -DELF_IMAGE -DAOUT_IMAGE
-endif
-
-# An alternate location for isolinux.bin can be set here
-# ISOLINUX_BIN=/path/to/isolinux.bin
diff --git a/gpxe/src/arch/i386/Makefile b/gpxe/src/arch/i386/Makefile
index 97ca0774..7d3e7639 100644
--- a/gpxe/src/arch/i386/Makefile
+++ b/gpxe/src/arch/i386/Makefile
@@ -1,3 +1,59 @@
+# Force i386-only instructions
+#
+CFLAGS += -march=i386
+
+# Code size reduction.
+#
+CFLAGS += -fstrength-reduce -fomit-frame-pointer
+
+# Code size reduction. gcc3 needs a different syntax to gcc2 if you
+# want to avoid spurious warnings.
+#
+GCC_VERSION := $(subst ., ,$(shell $(CC) -dumpversion))
+GCC_MAJOR := $(firstword $(GCC_VERSION))
+ifeq ($(GCC_MAJOR),2)
+CFLAGS += -malign-jumps=1 -malign-loops=1 -malign-functions=1
+else
+CFLAGS += -falign-jumps=1 -falign-loops=1 -falign-functions=1
+endif
+
+# Code size reduction. This is almost always a win. The kernel uses it, too.
+#
+CFLAGS += -mpreferred-stack-boundary=2
+
+# Code size reduction. Use regparm for all functions - C functions
+# called from assembly (or vice versa) need __cdecl now
+#
+CFLAGS += -mregparm=3
+
+# Code size reduction. Use -mrtd (same __cdecl requirements as above)
+CFLAGS += -mrtd
+
+# Code size reduction. This is the logical complement to -mregparm=3.
+# It doesn't currently buy us anything, but if anything ever tries to
+# return small structures, let's be prepared
+#
+CFLAGS += -freg-struct-return
+
+# Force 32-bit code even on an x86-64 machine
+#
+CFLAGS += -m32
+ASFLAGS += --32
+ifeq ($(HOST_OS),FreeBSD)
+LDFLAGS += -m elf_i386_fbsd
+else
+LDFLAGS += -m elf_i386
+endif
+
+# EFI requires -fshort-wchar, and nothing else currently uses wchar_t
+#
+CFLAGS += -fshort-wchar
+
+# We need to undefine the default macro "i386" when compiling .S
+# files, otherwise ".arch i386" translates to ".arch 1"...
+#
+CFLAGS += -Ui386
+
# Locations of utilities
#
ISOLINUX_BIN = /usr/lib/syslinux/isolinux.bin
@@ -12,6 +68,7 @@ SRCDIRS += arch/i386/drivers/net
SRCDIRS += arch/i386/interface/pcbios
SRCDIRS += arch/i386/interface/pxe
SRCDIRS += arch/i386/interface/syslinux
+SRCDIRS += arch/i386/interface/efi
# The various xxx_loader.c files are #included into core/loader.c and
# should not be compiled directly.
@@ -22,85 +79,32 @@ NON_AUTO_SRCS += arch/i386/core/wince_loader.c
# unnrv2b.S is used to generate a 16-bit as well as a 32-bit object.
#
-OBJS_unnrv2b = unnrv2b unnrv2b16
-CFLAGS_unnrv2b16 = -DCODE16
-
-# We need to undefine the default macro "i386" when compiling .S
-# files, otherwise ".arch i386" translates to ".arch 1"...
-#
-CFLAGS_S += -Ui386
+OBJS_unnrv2b = unnrv2b unnrv2b16
+CFLAGS_unnrv2b16 = -DCODE16
-# The i386 linker script
+# Include platform-specific Makefile
#
-LDSCRIPT = arch/i386/scripts/i386.lds
-
-# Media types.
-#
-MEDIA += rom
-MEDIA += pxe
-MEDIA += kpxe
-MEDIA += elf
-MEDIA += elfd
-MEDIA += lmelf
-MEDIA += lmelfd
-MEDIA += lkrn
-MEDIA += bImage
-MEDIA += dsk
-MEDIA += nbi
-MEDIA += hd
-MEDIA += raw
-MEDIA += com
-MEDIA += exe
-
-# Special target for building Master Boot Record binary
-$(BIN)/mbr.bin : $(BIN)/mbr.o
- $(OBJCOPY) -O binary $< $@
+MAKEDEPS += arch/i386/Makefile.$(PLATFORM)
+include arch/i386/Makefile.$(PLATFORM)
# Some suffixes (e.g. %.fd0) are generated directly from other
# finished files (e.g. %.dsk), rather than having their own prefix.
# rule to write disk images to /dev/fd0
-NON_AUTO_MEDIA += fd0
+NON_AUTO_MEDIA += fd0
%fd0 : %dsk
- dd if=$< bs=512 conv=sync of=/dev/fd0
- sync
+ $(QM)$(ECHO) " [DD] $@"
+ $(Q)dd if=$< bs=512 conv=sync of=/dev/fd0
+ $(Q)sync
# rule to create padded disk images
-NON_AUTO_MEDIA += pdsk
+NON_AUTO_MEDIA += pdsk
%pdsk : %dsk
- cp $< $@
- $(PERL) ./util/dskpad.pl $@
-
-# rule to make a non-emulation ISO boot image
-NON_AUTO_MEDIA += iso
-%iso: %lkrn util/geniso
- ISOLINUX_BIN=$(ISOLINUX_BIN) bash util/geniso $@ $<
-
-# rule to make a floppy emulation ISO boot image
-NON_AUTO_MEDIA += liso
-%liso: %lkrn util/genliso
- bash util/genliso $@ $<
-
-# rule to make a USB disk image
-$(BIN)/usbdisk.bin : $(BIN)/usbdisk.o
- $(OBJCOPY) -O binary $< $@
-
-NON_AUTO_MEDIA += usb
-%usb: $(BIN)/usbdisk.bin %hd
- cat $^ > $@
+ $(QM)$(ECHO) " [DSKPAD] $@"
+ $(Q)cp $< $@
+ $(Q)$(PERL) ./util/dskpad.pl $@
# Add NON_AUTO_MEDIA to the media list, so that they show up in the
# output of "make"
#
MEDIA += $(NON_AUTO_MEDIA)
-
-# Shortcut to allow typing just
-# make bin-kir/%
-# rather than
-# make -f arch/i386/kir-Makefile bin-kir/%
-# for building a KEEP_IT_REAL flavour.
-#
-$(BIN)-kir/% : kir-target
- $(MAKE) -f arch/i386/kir-Makefile $(MAKECMDGOALS)
-
-.PHONY : kir-target
diff --git a/gpxe/src/arch/i386/Makefile.efi b/gpxe/src/arch/i386/Makefile.efi
new file mode 100644
index 00000000..f1eb6fdf
--- /dev/null
+++ b/gpxe/src/arch/i386/Makefile.efi
@@ -0,0 +1,24 @@
+# -*- makefile -*- : Force emacs to use Makefile mode
+
+# The EFI linker script
+#
+LDSCRIPT = arch/i386/scripts/efi.lds
+
+# Use a relocatable link; we perform final relocations in the efilink utility.
+#
+LDFLAGS += -r -d -S
+
+# Media types.
+#
+NON_AUTO_MEDIA += efi
+
+# Rule for building EFI files
+#
+$(BIN)/%.efi.tmp-reloc : $(BIN)/%.efi.tmp $(EFILINK)
+ $(QM)$(ECHO) " [EFILINK] $@"
+ $(Q)$(LD) -e 0 -o /dev/null $< # Check for unresolved symbols
+ $(Q)$(EFILINK) $< $@
+
+$(BIN)/%.efi : $(BIN)/%.efi.tmp-reloc
+ $(QM)$(ECHO) " [FINISH] $@"
+ $(Q)$(OBJCOPY) -Obinary $< $@
diff --git a/gpxe/src/arch/i386/Makefile.pcbios b/gpxe/src/arch/i386/Makefile.pcbios
new file mode 100644
index 00000000..64b3dac2
--- /dev/null
+++ b/gpxe/src/arch/i386/Makefile.pcbios
@@ -0,0 +1,55 @@
+# -*- makefile -*- : Force emacs to use Makefile mode
+
+# The i386 linker script
+#
+LDSCRIPT = arch/i386/scripts/i386.lds
+
+# Stop ld from complaining about our customised linker script
+#
+LDFLAGS += -N --no-check-sections
+
+# Media types.
+#
+MEDIA += rom
+MEDIA += pxe
+MEDIA += kpxe
+MEDIA += kkpxe
+MEDIA += elf
+MEDIA += elfd
+MEDIA += lmelf
+MEDIA += lmelfd
+MEDIA += lkrn
+MEDIA += bImage
+MEDIA += dsk
+MEDIA += nbi
+MEDIA += hd
+MEDIA += raw
+MEDIA += com
+MEDIA += exe
+
+# rule to make a non-emulation ISO boot image
+NON_AUTO_MEDIA += iso
+%iso: %lkrn util/geniso
+ $(QM)$(ECHO) " [GENISO] $@"
+ $(Q)ISOLINUX_BIN=$(ISOLINUX_BIN) bash util/geniso $@ $<
+
+# rule to make a floppy emulation ISO boot image
+NON_AUTO_MEDIA += liso
+%liso: %lkrn util/genliso
+ $(QM)$(ECHO) " [GENLISO] $@"
+ $(Q)bash util/genliso $@ $<
+
+# Special target for building Master Boot Record binary
+$(BIN)/mbr.bin : $(BIN)/mbr.o
+ $(QM)$(ECHO) " [OBJCOPY] $@"
+ $(Q)$(OBJCOPY) -O binary $< $@
+
+# rule to make a USB disk image
+$(BIN)/usbdisk.bin : $(BIN)/usbdisk.o
+ $(QM)$(ECHO) " [OBJCOPY] $@"
+ $(Q)$(OBJCOPY) -O binary $< $@
+
+NON_AUTO_MEDIA += usb
+%usb: $(BIN)/usbdisk.bin %hd
+ $(QM)$(ECHO) " [FINISH] $@"
+ $(Q)cat $^ > $@
diff --git a/gpxe/src/arch/i386/core/gdbidt.S b/gpxe/src/arch/i386/core/gdbidt.S
index 860f7b01..64c29e4b 100644
--- a/gpxe/src/arch/i386/core/gdbidt.S
+++ b/gpxe/src/arch/i386/core/gdbidt.S
@@ -2,7 +2,7 @@
* Interrupt Descriptor Table (IDT) setup and interrupt handlers for GDB stub.
*/
-#include <virtaddr.h>
+#include <librm.h>
#define SIZEOF_I386_REGS 32
#define SIZEOF_I386_FLAGS 4
diff --git a/gpxe/src/arch/i386/core/gdbmach.c b/gpxe/src/arch/i386/core/gdbmach.c
index 5e72e4d0..d07663c4 100644
--- a/gpxe/src/arch/i386/core/gdbmach.c
+++ b/gpxe/src/arch/i386/core/gdbmach.c
@@ -19,7 +19,7 @@
#include <stddef.h>
#include <stdio.h>
#include <assert.h>
-#include <virtaddr.h>
+#include <gpxe/uaccess.h>
#include <gpxe/gdbstub.h>
#include <gdbmach.h>
diff --git a/gpxe/src/arch/i386/core/nap.c b/gpxe/src/arch/i386/core/nap.c
deleted file mode 100644
index 12bb5699..00000000
--- a/gpxe/src/arch/i386/core/nap.c
+++ /dev/null
@@ -1,12 +0,0 @@
-
-#include <realmode.h>
-#include <bios.h>
-
-/**************************************************************************
- * Save power by halting the CPU until the next interrupt
- **************************************************************************/
-void cpu_nap ( void ) {
- __asm__ __volatile__ ( REAL_CODE ( "sti\n\t"
- "hlt\n\t"
- "cli\n\t" ) : : );
-}
diff --git a/gpxe/src/arch/i386/core/pcidirect.c b/gpxe/src/arch/i386/core/pcidirect.c
index 2ed8c2ad..fec2e3c1 100644
--- a/gpxe/src/arch/i386/core/pcidirect.c
+++ b/gpxe/src/arch/i386/core/pcidirect.c
@@ -17,7 +17,6 @@
*/
#include <gpxe/pci.h>
-#include <pcidirect.h>
/** @file
*
@@ -36,3 +35,10 @@ void pcidirect_prepare ( struct pci_device *pci, int where ) {
( where & ~3 ) ), PCIDIRECT_CONFIG_ADDRESS );
}
+PROVIDE_PCIAPI_INLINE ( direct, pci_max_bus );
+PROVIDE_PCIAPI_INLINE ( direct, pci_read_config_byte );
+PROVIDE_PCIAPI_INLINE ( direct, pci_read_config_word );
+PROVIDE_PCIAPI_INLINE ( direct, pci_read_config_dword );
+PROVIDE_PCIAPI_INLINE ( direct, pci_write_config_byte );
+PROVIDE_PCIAPI_INLINE ( direct, pci_write_config_word );
+PROVIDE_PCIAPI_INLINE ( direct, pci_write_config_dword );
diff --git a/gpxe/src/arch/i386/core/pic8259.c b/gpxe/src/arch/i386/core/pic8259.c
index defe2e7d..8a0433dd 100644
--- a/gpxe/src/arch/i386/core/pic8259.c
+++ b/gpxe/src/arch/i386/core/pic8259.c
@@ -16,6 +16,7 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#include <gpxe/io.h>
#include <pic8259.h>
/** @file
diff --git a/gpxe/src/arch/i386/core/rdtsc_timer.c b/gpxe/src/arch/i386/core/rdtsc_timer.c
new file mode 100644
index 00000000..443c8ada
--- /dev/null
+++ b/gpxe/src/arch/i386/core/rdtsc_timer.c
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2008 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.
+ */
+
+/** @file
+ *
+ * RDTSC timer
+ *
+ */
+
+#include <assert.h>
+#include <gpxe/timer.h>
+#include <gpxe/timer2.h>
+
+/**
+ * Number of TSC ticks per microsecond
+ *
+ * This is calibrated on the first use of the timer.
+ */
+static unsigned long rdtsc_ticks_per_usec;
+
+/**
+ * Delay for a fixed number of microseconds
+ *
+ * @v usecs Number of microseconds for which to delay
+ */
+static void rdtsc_udelay ( unsigned long usecs ) {
+ unsigned long start;
+ unsigned long elapsed;
+
+ /* Sanity guard, since we may divide by this */
+ if ( ! usecs )
+ usecs = 1;
+
+ start = currticks();
+ if ( rdtsc_ticks_per_usec ) {
+ /* Already calibrated; busy-wait until done */
+ do {
+ elapsed = ( currticks() - start );
+ } while ( elapsed < ( usecs * rdtsc_ticks_per_usec ) );
+ } else {
+ /* Not yet calibrated; use timer2 and calibrate
+ * based on result.
+ */
+ timer2_udelay ( usecs );
+ elapsed = ( currticks() - start );
+ rdtsc_ticks_per_usec = ( elapsed / usecs );
+ DBG ( "RDTSC timer calibrated: %ld ticks in %ld usecs "
+ "(%ld MHz)\n", elapsed, usecs,
+ ( rdtsc_ticks_per_usec << TSC_SHIFT ) );
+ }
+}
+
+/**
+ * Get number of ticks per second
+ *
+ * @ret ticks_per_sec Number of ticks per second
+ */
+static unsigned long rdtsc_ticks_per_sec ( void ) {
+
+ /* Calibrate timer, if not already done */
+ if ( ! rdtsc_ticks_per_usec )
+ udelay ( 1 );
+
+ /* Sanity check */
+ assert ( rdtsc_ticks_per_usec != 0 );
+
+ return ( rdtsc_ticks_per_usec * 1000 * 1000 );
+}
+
+PROVIDE_TIMER ( rdtsc, udelay, rdtsc_udelay );
+PROVIDE_TIMER_INLINE ( rdtsc, currticks );
+PROVIDE_TIMER ( rdtsc, ticks_per_sec, rdtsc_ticks_per_sec );
diff --git a/gpxe/src/arch/i386/core/relocate.c b/gpxe/src/arch/i386/core/relocate.c
index aa58ad65..fd8df087 100644
--- a/gpxe/src/arch/i386/core/relocate.c
+++ b/gpxe/src/arch/i386/core/relocate.c
@@ -1,4 +1,4 @@
-#include <io.h>
+#include <gpxe/io.h>
#include <registers.h>
#include <gpxe/memmap.h>
@@ -18,8 +18,8 @@ extern char _max_align[];
#define max_align ( ( unsigned int ) _max_align )
/* Linker symbols */
-extern char _text[];
-extern char _end[];
+extern char _textdata[];
+extern char _etextdata[];
/* within 1MB of 4GB is too close.
* MAX_ADDR is the maximum address we can easily do DMA to.
@@ -47,8 +47,8 @@ __cdecl void relocate ( struct i386_all_regs *ix86 ) {
/* Get memory map and current location */
get_memmap ( &memmap );
- start = virt_to_phys ( _text );
- end = virt_to_phys ( _end );
+ start = virt_to_phys ( _textdata );
+ end = virt_to_phys ( _etextdata );
size = ( end - start );
padded_size = ( size + max_align - 1 );
diff --git a/gpxe/src/arch/i386/core/start32.S b/gpxe/src/arch/i386/core/start32.S
deleted file mode 100644
index 37ef5eb9..00000000
--- a/gpxe/src/arch/i386/core/start32.S
+++ /dev/null
@@ -1,325 +0,0 @@
-#include "virtaddr.h"
-
- .equ MSR_K6_EFER, 0xC0000080
- .equ EFER_LME, 0x00000100
- .equ X86_CR4_PAE, 0x00000020
- .equ CR0_PG, 0x80000000
-
-#ifdef GAS291
-#define DATA32 data32;
-#define ADDR32 addr32;
-#define LJMPI(x) ljmp x
-#else
-#define DATA32 data32
-#define ADDR32 addr32
-/* newer GAS295 require #define LJMPI(x) ljmp *x */
-#define LJMPI(x) ljmp x
-#endif
-
-/*
- * NOTE: if you write a subroutine that is called from C code (gcc/egcs),
- * then you only have to take care of %ebx, %esi, %edi and %ebp. These
- * registers must not be altered under any circumstance. All other registers
- * may be clobbered without any negative side effects. If you don't follow
- * this rule then you'll run into strange effects that only occur on some
- * gcc versions (because the register allocator may use different registers).
- *
- * All the data32 prefixes for the ljmp instructions are necessary, because
- * the assembler emits code with a relocation address of 0. This means that
- * all destinations are initially negative, which the assembler doesn't grok,
- * because for some reason negative numbers don't fit into 16 bits. The addr32
- * prefixes are there for the same reasons, because otherwise the memory
- * references are only 16 bit wide. Theoretically they are all superfluous.
- * One last note about prefixes: the data32 prefixes on all call _real_to_prot
- * instructions could be removed if the _real_to_prot function is changed to
- * deal correctly with 16 bit return addresses. I tried it, but failed.
- */
-
- .text
- .arch i386
- .code32
-
- /* This is a struct os_entry_regs */
- .globl os_regs
-os_regs: .space 56
-
-/**************************************************************************
-XSTART32 - Transfer control to the kernel just loaded
-**************************************************************************/
- .globl xstart32
-xstart32:
- /* Save the callee save registers */
- movl %ebp, os_regs + 32
- movl %esi, os_regs + 36
- movl %edi, os_regs + 40
- movl %ebx, os_regs + 44
-
- /* save the return address */
- popl %eax
- movl %eax, os_regs + 48
-
- /* save the stack pointer */
- movl %esp, os_regs + 52
-
- /* Get the new destination address */
- popl %ecx
-
- /* Store the physical address of xend on the stack */
- movl $xend32, %ebx
- addl virt_offset, %ebx
- pushl %ebx
-
- /* Store the destination address on the stack */
- pushl $PHYSICAL_CS
- pushl %ecx
-
- /* Cache virt_offset */
- movl virt_offset, %ebp
-
- /* Switch to using physical addresses */
- call _virt_to_phys
-
- /* Save the target stack pointer */
- movl %esp, os_regs + 12(%ebp)
- leal os_regs(%ebp), %esp
-
- /* Store the pointer to os_regs */
- movl %esp, os_regs_ptr(%ebp)
-
- /* Load my new registers */
- popal
- movl (-32 + 12)(%esp), %esp
-
- /* Jump to the new kernel
- * The lret switches to a flat code segment
- */
- lret
-
- .balign 4
- .globl xend32
-xend32:
- /* Fixup %eflags */
- nop
- cli
- cld
-
- /* Load %esp with &os_regs + virt_offset */
- .byte 0xbc /* movl $0, %esp */
-os_regs_ptr:
- .long 0
-
- /* Save the result registers */
- addl $32, %esp
- pushal
-
- /* Compute virt_offset */
- movl %esp, %ebp
- subl $os_regs, %ebp
-
- /* Load the stack pointer and convert it to physical address */
- movl 52(%esp), %esp
- addl %ebp, %esp
-
- /* Enable the virtual addresses */
- leal _phys_to_virt(%ebp), %eax
- call *%eax
-
- /* Restore the callee save registers */
- movl os_regs + 32, %ebp
- movl os_regs + 36, %esi
- movl os_regs + 40, %edi
- movl os_regs + 44, %ebx
- movl os_regs + 48, %edx
- movl os_regs + 52, %esp
-
- /* Get the C return value */
- movl os_regs + 28, %eax
-
- jmpl *%edx
-
-#ifdef CONFIG_X86_64
- .arch sledgehammer
-/**************************************************************************
-XSTART_lm - Transfer control to the kernel just loaded in long mode
-**************************************************************************/
- .globl xstart_lm
-xstart_lm:
- /* Save the callee save registers */
- pushl %ebp
- pushl %esi
- pushl %edi
- pushl %ebx
-
- /* Cache virt_offset && (virt_offset & 0xfffff000) */
- movl virt_offset, %ebp
- movl %ebp, %ebx
- andl $0xfffff000, %ebx
-
- /* Switch to using physical addresses */
- call _virt_to_phys
-
- /* Initialize the page tables */
- /* Level 4 */
- leal 0x23 + pgt_level3(%ebx), %eax
- leal pgt_level4(%ebx), %edi
- movl %eax, (%edi)
-
- /* Level 3 */
- leal 0x23 + pgt_level2(%ebx), %eax
- leal pgt_level3(%ebx), %edi
- movl %eax, 0x00(%edi)
- addl $4096, %eax
- movl %eax, 0x08(%edi)
- addl $4096, %eax
- movl %eax, 0x10(%edi)
- addl $4096, %eax
- movl %eax, 0x18(%edi)
-
- /* Level 2 */
- movl $0xe3, %eax
- leal pgt_level2(%ebx), %edi
- leal 16384(%edi), %esi
-pgt_level2_loop:
- movl %eax, (%edi)
- addl $8, %edi
- addl $0x200000, %eax
- cmp %esi, %edi
- jne pgt_level2_loop
-
- /* Point at the x86_64 page tables */
- leal pgt_level4(%ebx), %edi
- movl %edi, %cr3
-
-
- /* Setup for the return from 64bit mode */
- /* 64bit align the stack */
- movl %esp, %ebx /* original stack pointer + 16 */
- andl $0xfffffff8, %esp
-
- /* Save original stack pointer + 16 */
- pushl %ebx
-
- /* Save virt_offset */
- pushl %ebp
-
- /* Setup for the jmp to 64bit long mode */
- leal start_lm(%ebp), %eax
- movl %eax, 0x00 + start_lm_addr(%ebp)
- movl $LM_CODE_SEG, %eax
- movl %eax, 0x04 + start_lm_addr(%ebp)
-
- /* Setup for the jump out of 64bit long mode */
- leal end_lm(%ebp), %eax
- movl %eax, 0x00 + end_lm_addr(%ebp)
- movl $FLAT_CODE_SEG, %eax
- movl %eax, 0x04 + end_lm_addr(%ebp)
-
- /* Enable PAE mode */
- movl %cr4, %eax
- orl $X86_CR4_PAE, %eax
- movl %eax, %cr4
-
- /* Enable long mode */
- movl $MSR_K6_EFER, %ecx
- rdmsr
- orl $EFER_LME, %eax
- wrmsr
-
- /* Start paging, entering 32bit compatiblity mode */
- movl %cr0, %eax
- orl $CR0_PG, %eax
- movl %eax, %cr0
-
- /* Enter 64bit long mode */
- ljmp *start_lm_addr(%ebp)
- .code64
-start_lm:
- /* Load 64bit data segments */
- movl $LM_DATA_SEG, %eax
- movl %eax, %ds
- movl %eax, %es
- movl %eax, %ss
-
- andq $0xffffffff, %rbx
- /* Get the address to jump to */
- movl 20(%rbx), %edx
- andq $0xffffffff, %rdx
-
- /* Get the argument pointer */
- movl 24(%rbx), %ebx
- andq $0xffffffff, %rbx
-
- /* Jump to the 64bit code */
- call *%rdx
-
- /* Preserve the result */
- movl %eax, %edx
-
- /* Fixup %eflags */
- cli
- cld
-
- /* Switch to 32bit compatibility mode */
- ljmp *end_lm_addr(%rip)
-
- .code32
-end_lm:
- /* Disable paging */
- movl %cr0, %eax
- andl $~CR0_PG, %eax
- movl %eax, %cr0
-
- /* Disable long mode */
- movl $MSR_K6_EFER, %ecx
- rdmsr
- andl $~EFER_LME, %eax
- wrmsr
-
- /* Disable PAE */
- movl %cr4, %eax
- andl $~X86_CR4_PAE, %eax
- movl %eax, %cr4
-
- /* Compute virt_offset */
- popl %ebp
-
- /* Compute the original stack pointer + 16 */
- popl %ebx
- movl %ebx, %esp
-
- /* Enable the virtual addresses */
- leal _phys_to_virt(%ebp), %eax
- call *%eax
-
- /* Restore the callee save registers */
- popl %ebx
- popl %esi
- popl %edi
- popl %ebp
-
- /* Get the C return value */
- movl %edx, %eax
-
- /* Return */
- ret
-
- .arch i386
-#endif /* CONFIG_X86_64 */
-
-#ifdef CONFIG_X86_64
- .section ".bss"
- .p2align 12
- /* Include a dummy space in case we are loaded badly aligned */
- .space 4096
- /* Reserve enough space for a page table convering 4GB with 2MB pages */
-pgt_level4:
- .space 4096
-pgt_level3:
- .space 4096
-pgt_level2:
- .space 16384
-start_lm_addr:
- .space 8
-end_lm_addr:
- .space 8
-#endif
diff --git a/gpxe/src/arch/i386/core/i386_timer.c b/gpxe/src/arch/i386/core/timer2.c
index 8f90ae05..bb589ecc 100644
--- a/gpxe/src/arch/i386/core/i386_timer.c
+++ b/gpxe/src/arch/i386/core/timer2.c
@@ -12,12 +12,11 @@
*/
#include <stddef.h>
-#include <bits/timer2.h>
-#include <gpxe/timer.h>
-#include <io.h>
+#include <gpxe/timer2.h>
+#include <gpxe/io.h>
/* Timers tick over at this rate */
-#define TIMER2_TICK_RATE 1193180U
+#define TIMER2_TICKS_PER_SEC 1193180U
/* Parallel Peripheral Controller Port B */
#define PPC_PORTB 0x61
@@ -52,8 +51,7 @@
#define BINARY_COUNT 0x00
#define BCD_COUNT 0x01
-static void load_timer2(unsigned int ticks)
-{
+static void load_timer2 ( unsigned int ticks ) {
/*
* Now let's take care of PPC channel 2
*
@@ -75,15 +73,13 @@ static void load_timer2(unsigned int ticks)
outb(ticks >> 8, TIMER2_PORT);
}
-static int timer2_running(void)
-{
+static int timer2_running ( void ) {
return ((inb(PPC_PORTB) & PPCB_T2OUT) == 0);
}
-void i386_timer2_udelay(unsigned int usecs)
-{
- load_timer2((usecs * TIMER2_TICK_RATE)/USECS_IN_SEC);
- while (timer2_running())
- ;
+void timer2_udelay ( unsigned long usecs ) {
+ load_timer2 ( ( usecs * TIMER2_TICKS_PER_SEC ) / ( 1000 * 1000 ) );
+ while (timer2_running()) {
+ /* Do nothing */
+ }
}
-
diff --git a/gpxe/src/arch/i386/core/video_subr.c b/gpxe/src/arch/i386/core/video_subr.c
index bf82cc61..c821cd02 100644
--- a/gpxe/src/arch/i386/core/video_subr.c
+++ b/gpxe/src/arch/i386/core/video_subr.c
@@ -7,7 +7,7 @@
#include "stddef.h"
#include "string.h"
-#include "io.h"
+#include <gpxe/io.h>
#include "console.h"
#include <gpxe/init.h>
#include "vga.h"
diff --git a/gpxe/src/arch/i386/core/virtaddr.S b/gpxe/src/arch/i386/core/virtaddr.S
index 5d762375..cf6da4f6 100644
--- a/gpxe/src/arch/i386/core/virtaddr.S
+++ b/gpxe/src/arch/i386/core/virtaddr.S
@@ -4,7 +4,7 @@
*
*/
-#include "virtaddr.h"
+#include "librm.h"
.arch i386
.text
diff --git a/gpxe/src/arch/i386/core/x86_io.c b/gpxe/src/arch/i386/core/x86_io.c
new file mode 100644
index 00000000..424a96cc
--- /dev/null
+++ b/gpxe/src/arch/i386/core/x86_io.c
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2008 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 <gpxe/io.h>
+#include <gpxe/x86_io.h>
+
+/** @file
+ *
+ * gPXE I/O API for x86
+ *
+ */
+
+/**
+ * Read 64-bit qword from memory-mapped device
+ *
+ * @v io_addr I/O address
+ * @ret data Value read
+ *
+ * This routine uses MMX instructions.
+ */
+static uint64_t x86_readq ( volatile uint64_t *io_addr ) {
+ uint64_t data;
+ __asm__ __volatile__ ( "pushl %%edx\n\t"
+ "pushl %%eax\n\t"
+ "movq (%1), %%mm0\n\t"
+ "movq %%mm0, (%%esp)\n\t"
+ "popl %%eax\n\t"
+ "popl %%edx\n\t"
+ "emms\n\t"
+ : "=A" ( data ) : "r" ( io_addr ) );
+ return data;
+}
+
+/**
+ * Write 64-bit qword to memory-mapped device
+ *
+ * @v data Value to write
+ * @v io_addr I/O address
+ *
+ * This routine uses MMX instructions.
+ */
+static void x86_writeq ( uint64_t data, volatile uint64_t *io_addr ) {
+ __asm__ __volatile__ ( "pushl %%edx\n\t"
+ "pushl %%eax\n\t"
+ "movq (%%esp), %%mm0\n\t"
+ "movq %%mm0, (%1)\n\t"
+ "popl %%eax\n\t"
+ "popl %%edx\n\t"
+ "emms\n\t"
+ : : "A" ( data ), "r" ( io_addr ) );
+}
+
+PROVIDE_IOAPI_INLINE ( x86, phys_to_bus );
+PROVIDE_IOAPI_INLINE ( x86, bus_to_phys );
+PROVIDE_IOAPI_INLINE ( x86, ioremap );
+PROVIDE_IOAPI_INLINE ( x86, iounmap );
+PROVIDE_IOAPI_INLINE ( x86, io_to_bus );
+PROVIDE_IOAPI_INLINE ( x86, readb );
+PROVIDE_IOAPI_INLINE ( x86, readw );
+PROVIDE_IOAPI_INLINE ( x86, readl );
+PROVIDE_IOAPI ( x86, readq, x86_readq );
+PROVIDE_IOAPI_INLINE ( x86, writeb );
+PROVIDE_IOAPI_INLINE ( x86, writew );
+PROVIDE_IOAPI_INLINE ( x86, writel );
+PROVIDE_IOAPI ( x86, writeq, x86_writeq );
+PROVIDE_IOAPI_INLINE ( x86, inb );
+PROVIDE_IOAPI_INLINE ( x86, inw );
+PROVIDE_IOAPI_INLINE ( x86, inl );
+PROVIDE_IOAPI_INLINE ( x86, outb );
+PROVIDE_IOAPI_INLINE ( x86, outw );
+PROVIDE_IOAPI_INLINE ( x86, outl );
+PROVIDE_IOAPI_INLINE ( x86, insb );
+PROVIDE_IOAPI_INLINE ( x86, insw );
+PROVIDE_IOAPI_INLINE ( x86, insl );
+PROVIDE_IOAPI_INLINE ( x86, outsb );
+PROVIDE_IOAPI_INLINE ( x86, outsw );
+PROVIDE_IOAPI_INLINE ( x86, outsl );
+PROVIDE_IOAPI_INLINE ( x86, iodelay );
+PROVIDE_IOAPI_INLINE ( x86, mb );
diff --git a/gpxe/src/arch/i386/drivers/net/undinet.c b/gpxe/src/arch/i386/drivers/net/undinet.c
index 9576ad60..6ce4d924 100644
--- a/gpxe/src/arch/i386/drivers/net/undinet.c
+++ b/gpxe/src/arch/i386/drivers/net/undinet.c
@@ -23,6 +23,7 @@
#include <biosint.h>
#include <pnpbios.h>
#include <basemem_packet.h>
+#include <gpxe/io.h>
#include <gpxe/iobuf.h>
#include <gpxe/netdevice.h>
#include <gpxe/if_ether.h>
@@ -554,7 +555,7 @@ static int undinet_open ( struct net_device *netdev ) {
DBGC ( undinic, "UNDINIC %p opened\n", undinic );
return 0;
-err:
+ err:
undinet_close ( netdev );
return rc;
}
@@ -595,10 +596,6 @@ static void undinet_close ( struct net_device *netdev ) {
/* Disable interrupt and unhook ISR */
disable_irq ( undinic->irq );
undinet_unhook_isr ( undinic->irq );
-#if 0
- enable_irq ( undinic->irq );
- send_eoi ( undinic->irq );
-#endif
DBGC ( undinic, "UNDINIC %p closed\n", undinic );
}
@@ -642,9 +639,7 @@ int undinet_probe ( struct undi_device *undi ) {
struct s_PXENV_UNDI_GET_IFACE_INFO undi_iface;
struct s_PXENV_UNDI_SHUTDOWN undi_shutdown;
struct s_PXENV_UNDI_CLEANUP undi_cleanup;
-#if 0
struct s_PXENV_STOP_UNDI stop_undi;
-#endif
int rc;
/* Allocate net device */
@@ -671,20 +666,23 @@ int undinet_probe ( struct undi_device *undi ) {
&start_undi,
sizeof ( start_undi ) ) ) != 0 )
goto err_start_undi;
- /* Bring up UNDI stack */
+ }
+ undi->flags |= UNDI_FL_STARTED;
+
+ /* Bring up UNDI stack */
+ if ( ! ( undi->flags & UNDI_FL_INITIALIZED ) ) {
memset ( &undi_startup, 0, sizeof ( undi_startup ) );
if ( ( rc = undinet_call ( undinic, PXENV_UNDI_STARTUP,
&undi_startup,
sizeof ( undi_startup ) ) ) != 0 )
- goto err_undi_startup;
-
+ goto err_undi_startup;
memset ( &undi_initialize, 0, sizeof ( undi_initialize ) );
if ( ( rc = undinet_call ( undinic, PXENV_UNDI_INITIALIZE,
&undi_initialize,
- sizeof ( undi_initialize ) ) ) != 0 )
- goto err_undi_initialize;
+ sizeof ( undi_initialize ))) != 0 )
+ goto err_undi_initialize;
}
- undi->flags |= UNDI_FL_STARTED;
+ undi->flags |= UNDI_FL_INITIALIZED;
/* Get device information */
memset ( &undi_info, 0, sizeof ( undi_info ) );
@@ -731,7 +729,6 @@ int undinet_probe ( struct undi_device *undi ) {
err_bad_irq:
err_undi_get_information:
err_undi_initialize:
-
/* Shut down UNDI stack */
memset ( &undi_shutdown, 0, sizeof ( undi_shutdown ) );
undinet_call ( undinic, PXENV_UNDI_SHUTDOWN, &undi_shutdown,
@@ -739,13 +736,13 @@ int undinet_probe ( struct undi_device *undi ) {
memset ( &undi_cleanup, 0, sizeof ( undi_cleanup ) );
undinet_call ( undinic, PXENV_UNDI_CLEANUP, &undi_cleanup,
sizeof ( undi_cleanup ) );
+ undi->flags &= ~UNDI_FL_INITIALIZED;
err_undi_startup:
-#if 0
/* Unhook UNDI stack */
memset ( &stop_undi, 0, sizeof ( stop_undi ) );
undinet_call ( undinic, PXENV_STOP_UNDI, &stop_undi,
sizeof ( stop_undi ) );
-#endif
+ undi->flags &= ~UNDI_FL_STARTED;
err_start_undi:
netdev_nullify ( netdev );
netdev_put ( netdev );
@@ -761,30 +758,33 @@ int undinet_probe ( struct undi_device *undi ) {
void undinet_remove ( struct undi_device *undi ) {
struct net_device *netdev = undi_get_drvdata ( undi );
struct undi_nic *undinic = netdev->priv;
-#if 0
struct s_PXENV_UNDI_SHUTDOWN undi_shutdown;
struct s_PXENV_UNDI_CLEANUP undi_cleanup;
struct s_PXENV_STOP_UNDI stop_undi;
-#endif
/* Unregister net device */
unregister_netdev ( netdev );
- /* Shut down UNDI stack */
-#if 0
- memset ( &undi_shutdown, 0, sizeof ( undi_shutdown ) );
- undinet_call ( undinic, PXENV_UNDI_SHUTDOWN, &undi_shutdown,
- sizeof ( undi_shutdown ) );
- memset ( &undi_cleanup, 0, sizeof ( undi_cleanup ) );
- undinet_call ( undinic, PXENV_UNDI_CLEANUP, &undi_cleanup,
- sizeof ( undi_cleanup ) );
-
- /* Unhook UNDI stack */
- memset ( &stop_undi, 0, sizeof ( stop_undi ) );
- undinet_call ( undinic, PXENV_STOP_UNDI, &stop_undi,
- sizeof ( stop_undi ) );
- undi->flags &= ~UNDI_FL_STARTED;
-#endif
+ /* If we are preparing for an OS boot, or if we cannot exit
+ * via the PXE stack, then shut down the PXE stack.
+ */
+ if ( ! ( undi->flags & UNDI_FL_KEEP_ALL ) ) {
+
+ /* Shut down UNDI stack */
+ memset ( &undi_shutdown, 0, sizeof ( undi_shutdown ) );
+ undinet_call ( undinic, PXENV_UNDI_SHUTDOWN, &undi_shutdown,
+ sizeof ( undi_shutdown ) );
+ memset ( &undi_cleanup, 0, sizeof ( undi_cleanup ) );
+ undinet_call ( undinic, PXENV_UNDI_CLEANUP, &undi_cleanup,
+ sizeof ( undi_cleanup ) );
+ undi->flags &= ~UNDI_FL_INITIALIZED;
+
+ /* Unhook UNDI stack */
+ memset ( &stop_undi, 0, sizeof ( stop_undi ) );
+ undinet_call ( undinic, PXENV_STOP_UNDI, &stop_undi,
+ sizeof ( stop_undi ) );
+ undi->flags &= ~UNDI_FL_STARTED;
+ }
/* Clear entry point */
memset ( &undinet_entry_point, 0, sizeof ( undinet_entry_point ) );
diff --git a/gpxe/src/arch/i386/drivers/net/undionly.c b/gpxe/src/arch/i386/drivers/net/undionly.c
index ee361493..4cdce677 100644
--- a/gpxe/src/arch/i386/drivers/net/undionly.c
+++ b/gpxe/src/arch/i386/drivers/net/undionly.c
@@ -20,6 +20,7 @@
#include <stdlib.h>
#include <string.h>
#include <gpxe/device.h>
+#include <gpxe/init.h>
#include <undi.h>
#include <undinet.h>
#include <undipreload.h>
@@ -107,3 +108,20 @@ struct root_device undi_root_device __root_device = {
.dev = { .name = "UNDI" },
.driver = &undi_root_driver,
};
+
+/**
+ * Prepare for exit
+ *
+ * @v flags Shutdown flags
+ */
+static void undionly_shutdown ( int flags ) {
+ /* If we are shutting down to boot an OS, clear the "keep PXE
+ * stack" flag.
+ */
+ if ( flags & SHUTDOWN_BOOT )
+ preloaded_undi.flags &= ~UNDI_FL_KEEP_ALL;
+}
+
+struct startup_fn startup_undionly __startup_fn ( STARTUP_LATE ) = {
+ .shutdown = undionly_shutdown,
+};
diff --git a/gpxe/src/arch/i386/drivers/timer_bios.c b/gpxe/src/arch/i386/drivers/timer_bios.c
deleted file mode 100644
index f9caf8d9..00000000
--- a/gpxe/src/arch/i386/drivers/timer_bios.c
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Etherboot routines for PCBIOS firmware.
- *
- * Body of routines taken from old pcbios.S
- */
-
-#include <gpxe/init.h>
-#include <gpxe/timer.h>
-#include <stdio.h>
-#include <realmode.h>
-#include <bios.h>
-#include <bits/timer2.h>
-
-/* A bit faster actually, but we don't care. */
-#define TIMER2_TICKS_PER_SEC 18
-
-/*
- * Use direct memory access to BIOS variables, longword 0040:006C (ticks
- * today) and byte 0040:0070 (midnight crossover flag) instead of calling
- * timeofday BIOS interrupt.
- */
-
-static tick_t bios_currticks ( void ) {
- static int days = 0;
- uint32_t ticks;
- uint8_t midnight;
-
- /* Re-enable interrupts so that the timer interrupt can occur */
- __asm__ __volatile__ ( REAL_CODE ( "sti\n\t"
- "nop\n\t"
- "nop\n\t"
- "cli\n\t" ) : : );
-
- get_real ( ticks, BDA_SEG, 0x006c );
- get_real ( midnight, BDA_SEG, 0x0070 );
-
- if ( midnight ) {
- midnight = 0;
- put_real ( midnight, BDA_SEG, 0x0070 );
- days += 0x1800b0;
- }
-
- return ( (days + ticks) * (USECS_IN_SEC / TIMER2_TICKS_PER_SEC) );
-}
-
-static int bios_ts_init(void)
-{
- DBG("BIOS timer installed\n");
- return 0;
-}
-
-struct timer bios_ts __timer ( 02 ) = {
- .init = bios_ts_init,
- .udelay = i386_timer2_udelay,
- .currticks = bios_currticks,
-};
-
diff --git a/gpxe/src/arch/i386/drivers/timer_rdtsc.c b/gpxe/src/arch/i386/drivers/timer_rdtsc.c
deleted file mode 100644
index 09b7df2f..00000000
--- a/gpxe/src/arch/i386/drivers/timer_rdtsc.c
+++ /dev/null
@@ -1,69 +0,0 @@
-
-#include <gpxe/init.h>
-#include <gpxe/timer.h>
-#include <errno.h>
-#include <stdio.h>
-#include <bits/cpu.h>
-#include <bits/timer2.h>
-#include <io.h>
-
-
-#define rdtsc(low,high) \
- __asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high))
-
-#define rdtscll(val) \
- __asm__ __volatile__ ("rdtsc" : "=A" (val))
-
-
-/* Measure how many clocks we get in one microsecond */
-static inline uint64_t calibrate_tsc(void)
-{
-
- uint64_t rdtsc_start;
- uint64_t rdtsc_end;
-
- rdtscll(rdtsc_start);
- i386_timer2_udelay(USECS_IN_MSEC);
- rdtscll(rdtsc_end);
-
- return (rdtsc_end - rdtsc_start) / USECS_IN_MSEC;
-}
-
-static uint32_t clocks_per_usec = 0;
-
-/* We measure time in microseconds. */
-static tick_t rdtsc_currticks(void)
-{
- uint64_t clocks;
-
- /* Read the Time Stamp Counter */
- rdtscll(clocks);
-
- return clocks / clocks_per_usec;
-}
-
-static int rdtsc_ts_init(void)
-{
-
- struct cpuinfo_x86 cpu_info;
-
- get_cpuinfo(&cpu_info);
- if (cpu_info.features & X86_FEATURE_TSC) {
- clocks_per_usec= calibrate_tsc();
- if (clocks_per_usec) {
- DBG("RDTSC ticksource installed. CPU running at %ld Mhz\n",
- clocks_per_usec);
- return 0;
- }
- }
-
- DBG("RDTSC ticksource not available on this machine.\n");
- return -ENODEV;
-}
-
-struct timer rdtsc_ts __timer (01) = {
- .init = rdtsc_ts_init,
- .udelay = generic_currticks_udelay,
- .currticks = rdtsc_currticks,
-};
-
diff --git a/gpxe/src/arch/i386/firmware/pcbios/e820mangler.S b/gpxe/src/arch/i386/firmware/pcbios/e820mangler.S
index 4fbd6563..53e2d7c5 100644
--- a/gpxe/src/arch/i386/firmware/pcbios/e820mangler.S
+++ b/gpxe/src/arch/i386/firmware/pcbios/e820mangler.S
@@ -66,7 +66,7 @@
.align 16
.globl hidemem_base
.globl hidemem_umalloc
- .globl hidemem_text
+ .globl hidemem_textdata
memory_windows:
base_memory_window: .long 0x00000000, 0x00000000 /* Start of memory */
@@ -76,7 +76,7 @@ ext_memory_window: .long 0x000a0000, 0x00000000 /* 640kB mark */
hidemem_umalloc: .long 0xffffffff, 0xffffffff /* Changes at runtime */
.long 0xffffffff, 0xffffffff /* Changes at runtime */
-hidemem_text: .long 0xffffffff, 0xffffffff /* Changes at runtime */
+hidemem_textdata: .long 0xffffffff, 0xffffffff /* Changes at runtime */
.long 0xffffffff, 0xffffffff /* Changes at runtime */
.long 0xffffffff, 0xffffffff /* End of memory */
@@ -268,8 +268,10 @@ get_underlying_e820:
pushl %ebx
pushl %ecx
pushl %edx
+ pushl %esi /* Some implementations corrupt %esi, so we */
+ pushl %edi /* preserve %esi, %edi and %ebp to be paranoid */
+ pushl %ebp
pushw %es
- pushw %di
pushw %ds
popw %es
movw $underlying_e820_cache, %di
@@ -280,8 +282,10 @@ get_underlying_e820:
stc
pushfw
lcall *%cs:int15_vector
- popw %di
popw %es
+ popl %ebp
+ popl %edi
+ popl %esi
/* Check for error return from underlying e820 call */
jc 2f /* CF set: error */
cmpl $SMAP, %eax
diff --git a/gpxe/src/arch/i386/firmware/pcbios/gateA20.c b/gpxe/src/arch/i386/firmware/pcbios/gateA20.c
index a14e3416..34e3ac52 100644
--- a/gpxe/src/arch/i386/firmware/pcbios/gateA20.c
+++ b/gpxe/src/arch/i386/firmware/pcbios/gateA20.c
@@ -1,6 +1,7 @@
#include <stdio.h>
#include <realmode.h>
#include <bios.h>
+#include <gpxe/io.h>
#include <gpxe/timer.h>
#define K_RDWR 0x60 /* keyboard data & cmds (read/write) */
@@ -48,9 +49,9 @@ static void empty_8042 ( void ) {
time = currticks() + TICKS_PER_SEC; /* max wait of 1 second */
while ( ( inb ( K_CMD ) & ( K_IBUF_FUL | K_OBUF_FUL ) ) &&
currticks() < time ) {
- SLOW_DOWN_IO;
- ( void ) inb ( K_RDWR );
- SLOW_DOWN_IO;
+ iodelay();
+ ( void ) inb_p ( K_RDWR );
+ iodelay();
}
}
@@ -77,7 +78,7 @@ static int gateA20_is_set ( int retries ) {
/* Avoid false negatives */
test_pattern++;
- SLOW_DOWN_IO;
+ iodelay();
/* Always retry at least once, to avoid false negatives */
} while ( retries-- >= 0 );
@@ -145,9 +146,9 @@ void gateA20_set ( void ) {
scp_a = inb ( SCP_A );
scp_a &= ~0x01; /* Avoid triggering a reset */
scp_a |= 0x02; /* Enable A20 */
- SLOW_DOWN_IO;
+ iodelay();
outb ( scp_a, SCP_A );
- SLOW_DOWN_IO;
+ iodelay();
if ( gateA20_is_set ( A20_SCPA_RETRIES ) ) {
DBG ( "Enabled gate A20 using "
"Fast Gate A20\n" );
diff --git a/gpxe/src/arch/i386/firmware/pcbios/hidemem.c b/gpxe/src/arch/i386/firmware/pcbios/hidemem.c
index c9df7bd0..620b62e0 100644
--- a/gpxe/src/arch/i386/firmware/pcbios/hidemem.c
+++ b/gpxe/src/arch/i386/firmware/pcbios/hidemem.c
@@ -55,8 +55,8 @@ extern struct hidden_region __data16 ( hidemem_umalloc );
#define hidemem_umalloc __use_data16 ( hidemem_umalloc )
/** Hidden text memory */
-extern struct hidden_region __data16 ( hidemem_text );
-#define hidemem_text __use_data16 ( hidemem_text )
+extern struct hidden_region __data16 ( hidemem_textdata );
+#define hidemem_textdata __use_data16 ( hidemem_textdata )
/** Assembly routine in e820mangler.S */
extern void int15();
@@ -66,12 +66,12 @@ extern struct segoff __text16 ( int15_vector );
#define int15_vector __use_text16 ( int15_vector )
/* The linker defines these symbols for us */
-extern char _text[];
-extern char _end[];
-extern char _text16_size[];
-#define _text16_size ( ( unsigned int ) _text16_size )
-extern char _data16_size[];
-#define _data16_size ( ( unsigned int ) _data16_size )
+extern char _textdata[];
+extern char _etextdata[];
+extern char _text16_memsz[];
+#define _text16_memsz ( ( unsigned int ) _text16_memsz )
+extern char _data16_memsz[];
+#define _data16_memsz ( ( unsigned int ) _data16_memsz )
/**
* Hide region of memory from system memory map
@@ -110,7 +110,7 @@ void hide_basemem ( void ) {
*
*/
void hide_umalloc ( physaddr_t start, physaddr_t end ) {
- assert ( end <= virt_to_phys ( _text ) );
+ assert ( end <= virt_to_phys ( _textdata ) );
hide_region ( &hidemem_umalloc, start, end );
}
@@ -118,9 +118,9 @@ void hide_umalloc ( physaddr_t start, physaddr_t end ) {
* Hide .text and .data
*
*/
-void hide_text ( void ) {
- hide_region ( &hidemem_text, virt_to_phys ( _text ),
- virt_to_phys ( _end ) );
+void hide_textdata ( void ) {
+ hide_region ( &hidemem_textdata, virt_to_phys ( _textdata ),
+ virt_to_phys ( _etextdata ) );
}
/**
@@ -148,8 +148,8 @@ static void hide_etherboot ( void ) {
/* Initialise the hidden regions */
hide_basemem();
- hide_umalloc ( virt_to_phys ( _text ), virt_to_phys ( _text ) );
- hide_text();
+ hide_umalloc ( virt_to_phys ( _textdata ), virt_to_phys ( _textdata ) );
+ hide_textdata();
/* Some really moronic BIOSes bring up the PXE stack via the
* UNDI loader entry point and then don't bother to unload it
@@ -161,8 +161,8 @@ static void hide_etherboot ( void ) {
* We use a heuristic to guess whether or not we are being
* loaded sensibly.
*/
- rm_cs_top = ( ( ( rm_cs << 4 ) + _text16_size + 1024 - 1 ) >> 10 );
- rm_ds_top = ( ( ( rm_ds << 4 ) + _data16_size + 1024 - 1 ) >> 10 );
+ rm_cs_top = ( ( ( rm_cs << 4 ) + _text16_memsz + 1024 - 1 ) >> 10 );
+ rm_ds_top = ( ( ( rm_ds << 4 ) + _data16_memsz + 1024 - 1 ) >> 10 );
fbms = get_fbms();
if ( ( rm_cs_top < fbms ) && ( rm_ds_top < fbms ) ) {
DBG ( "Detected potentially unsafe UNDI load at CS=%04x "
diff --git a/gpxe/src/arch/i386/firmware/pcbios/memmap.c b/gpxe/src/arch/i386/firmware/pcbios/memmap.c
index 9de10a7a..2e9627c0 100644
--- a/gpxe/src/arch/i386/firmware/pcbios/memmap.c
+++ b/gpxe/src/arch/i386/firmware/pcbios/memmap.c
@@ -158,7 +158,7 @@ static int meme820 ( struct memory_map *memmap ) {
uint32_t smap;
size_t size;
unsigned int flags;
- unsigned int discard_d, discard_D;
+ unsigned int discard_D;
/* Clear the E820 buffer. Do this once before starting,
* rather than on each call; some BIOSes rely on the contents
@@ -167,18 +167,24 @@ static int meme820 ( struct memory_map *memmap ) {
memset ( &e820buf, 0, sizeof ( e820buf ) );
do {
- __asm__ __volatile__ ( REAL_CODE ( "stc\n\t"
+ /* Some BIOSes corrupt %esi for fun. Guard against
+ * this by telling gcc that all non-output registers
+ * may be corrupted.
+ */
+ __asm__ __volatile__ ( REAL_CODE ( "pushl %%ebp\n\t"
+ "stc\n\t"
"int $0x15\n\t"
"pushfw\n\t"
- "popw %w0\n\t" )
- : "=r" ( flags ), "=a" ( smap ),
- "=b" ( next ), "=D" ( discard_D ),
- "=c" ( size ), "=d" ( discard_d )
+ "popw %%dx\n\t"
+ "popl %%ebp\n\t" )
+ : "=a" ( smap ), "=b" ( next ),
+ "=c" ( size ), "=d" ( flags ),
+ "=D" ( discard_D )
: "a" ( 0xe820 ), "b" ( next ),
"D" ( __from_data16 ( &e820buf ) ),
"c" ( sizeof ( e820buf ) ),
"d" ( SMAP )
- : "memory" );
+ : "esi", "memory" );
if ( smap != SMAP ) {
DBG ( "INT 15,e820 failed SMAP signature check\n" );
diff --git a/gpxe/src/arch/i386/firmware/pcbios/smbios_settings.c b/gpxe/src/arch/i386/firmware/pcbios/smbios_settings.c
index b088e51d..3238fb19 100644
--- a/gpxe/src/arch/i386/firmware/pcbios/smbios_settings.c
+++ b/gpxe/src/arch/i386/firmware/pcbios/smbios_settings.c
@@ -24,6 +24,16 @@
#include <gpxe/uuid.h>
#include <smbios.h>
+/** SMBIOS settings tag magic number */
+#define SMBIOS_TAG_MAGIC 0x5B /* "SmBios" */
+
+/**
+ * Construct SMBIOS empty tag
+ *
+ * @ret tag SMBIOS setting tag
+ */
+#define SMBIOS_EMPTY_TAG ( SMBIOS_TAG_MAGIC << 24 )
+
/**
* Construct SMBIOS raw-data tag
*
@@ -33,7 +43,8 @@
* @ret tag SMBIOS setting tag
*/
#define SMBIOS_RAW_TAG( _type, _structure, _field ) \
- ( ( (_type) << 16 ) | \
+ ( ( SMBIOS_TAG_MAGIC << 24 ) | \
+ ( (_type) << 16 ) | \
( offsetof ( _structure, _field ) << 8 ) | \
( sizeof ( ( ( _structure * ) 0 )->_field ) ) )
@@ -46,7 +57,8 @@
* @ret tag SMBIOS setting tag
*/
#define SMBIOS_STRING_TAG( _type, _structure, _field ) \
- ( ( (_type) << 16 ) | \
+ ( ( SMBIOS_TAG_MAGIC << 24 ) | \
+ ( (_type) << 16 ) | \
( offsetof ( _structure, _field ) << 8 ) )
/**
@@ -78,16 +90,18 @@ static int smbios_fetch ( struct settings *settings __unused,
struct setting *setting,
void *data, size_t len ) {
struct smbios_structure structure;
+ unsigned int tag_magic;
unsigned int tag_type;
unsigned int tag_offset;
unsigned int tag_len;
int rc;
/* Split tag into type, offset and length */
- tag_type = ( setting->tag >> 16 );
+ tag_magic = ( setting->tag >> 24 );
+ tag_type = ( ( setting->tag >> 16 ) & 0xff );
tag_offset = ( ( setting->tag >> 8 ) & 0xff );
tag_len = ( setting->tag & 0xff );
- if ( ! tag_type )
+ if ( tag_magic != SMBIOS_TAG_MAGIC )
return -ENOENT;
/* Find SMBIOS structure */
@@ -127,6 +141,7 @@ static struct settings_operations smbios_settings_operations = {
static struct settings smbios_settings = {
.refcnt = NULL,
.name = "smbios",
+ .tag_magic = SMBIOS_EMPTY_TAG,
.siblings = LIST_HEAD_INIT ( smbios_settings.siblings ),
.children = LIST_HEAD_INIT ( smbios_settings.children ),
.op = &smbios_settings_operations,
diff --git a/gpxe/src/arch/i386/image/multiboot.c b/gpxe/src/arch/i386/image/multiboot.c
index a4a340fd..49adf951 100644
--- a/gpxe/src/arch/i386/image/multiboot.c
+++ b/gpxe/src/arch/i386/image/multiboot.c
@@ -282,11 +282,13 @@ static int multiboot_exec ( struct image *image ) {
/* Jump to OS with flat physical addressing */
DBGC ( image, "MULTIBOOT %p starting execution at %lx\n",
image, entry );
- __asm__ __volatile__ ( PHYS_CODE ( "call *%%edi\n\t" )
+ __asm__ __volatile__ ( PHYS_CODE ( "pushl %%ebp\n\t"
+ "call *%%edi\n\t"
+ "popl %%ebp\n\t" )
: : "a" ( MULTIBOOT_BOOTLOADER_MAGIC ),
"b" ( virt_to_phys ( &mbinfo ) ),
"D" ( entry )
- : "ecx", "edx", "esi", "ebp", "memory" );
+ : "ecx", "edx", "esi", "memory" );
DBGC ( image, "MULTIBOOT %p returned\n", image );
diff --git a/gpxe/src/arch/i386/image/nbi.c b/gpxe/src/arch/i386/image/nbi.c
index e6a0ab0f..ea8375cb 100644
--- a/gpxe/src/arch/i386/image/nbi.c
+++ b/gpxe/src/arch/i386/image/nbi.c
@@ -372,11 +372,12 @@ static int nbi_boot32 ( struct image *image, struct imgheader *imgheader ) {
* @ret netdev Boot network device
*/
static struct net_device * guess_boot_netdev ( void ) {
- struct net_device *boot_netdev;
+ struct net_device *netdev;
/* Just use the first network device */
- for_each_netdev ( boot_netdev ) {
- return boot_netdev;
+ for_each_netdev ( netdev ) {
+ if ( netdev->state & NETDEV_OPEN )
+ return netdev;
}
return NULL;
diff --git a/gpxe/src/arch/i386/include/bios.h b/gpxe/src/arch/i386/include/bios.h
index 630a898b..979a092c 100644
--- a/gpxe/src/arch/i386/include/bios.h
+++ b/gpxe/src/arch/i386/include/bios.h
@@ -5,7 +5,4 @@
#define BDA_FBMS 0x0013
#define BDA_NUM_DRIVES 0x0075
-extern unsigned long currticks ( void );
-extern void cpu_nap ( void );
-
#endif /* BIOS_H */
diff --git a/gpxe/src/arch/i386/include/biosint.h b/gpxe/src/arch/i386/include/biosint.h
index d4e34963..d365cf01 100644
--- a/gpxe/src/arch/i386/include/biosint.h
+++ b/gpxe/src/arch/i386/include/biosint.h
@@ -6,9 +6,22 @@
*
*/
+#include <realmode.h>
+
struct segoff;
-extern int hooked_bios_interrupts;
+/**
+ * Hooked interrupt count
+ *
+ * At exit, after unhooking all possible interrupts, this counter
+ * should be examined. If it is non-zero, it means that we failed to
+ * unhook at least one interrupt vector, and so must not free up the
+ * memory we are using. (Note that this also implies that we should
+ * re-hook INT 15 in order to hide ourselves from the memory map).
+ */
+extern uint16_t __text16 ( hooked_bios_interrupts );
+#define hooked_bios_interrupts __use_text16 ( hooked_bios_interrupts )
+
extern void hook_bios_interrupt ( unsigned int interrupt, unsigned int handler,
struct segoff *chain_vector );
extern int unhook_bios_interrupt ( unsigned int interrupt,
diff --git a/gpxe/src/arch/i386/include/bits/errfile.h b/gpxe/src/arch/i386/include/bits/errfile.h
index 99927c28..70c78eaf 100644
--- a/gpxe/src/arch/i386/include/bits/errfile.h
+++ b/gpxe/src/arch/i386/include/bits/errfile.h
@@ -6,7 +6,7 @@
* @{
*/
-#define ERRFILE_umalloc ( ERRFILE_ARCH | ERRFILE_CORE | 0x00000000 )
+#define ERRFILE_memtop_umalloc ( ERRFILE_ARCH | ERRFILE_CORE | 0x00000000 )
#define ERRFILE_memmap ( ERRFILE_ARCH | ERRFILE_CORE | 0x00010000 )
#define ERRFILE_pnpbios ( ERRFILE_ARCH | ERRFILE_CORE | 0x00020000 )
#define ERRFILE_smbios ( ERRFILE_ARCH | ERRFILE_CORE | 0x00030000 )
diff --git a/gpxe/src/arch/i386/include/bits/io.h b/gpxe/src/arch/i386/include/bits/io.h
new file mode 100644
index 00000000..dd0ee444
--- /dev/null
+++ b/gpxe/src/arch/i386/include/bits/io.h
@@ -0,0 +1,12 @@
+#ifndef _BITS_IO_H
+#define _BITS_IO_H
+
+/** @file
+ *
+ * i386-specific I/O API implementations
+ *
+ */
+
+#include <gpxe/x86_io.h>
+
+#endif /* _BITS_IO_H */
diff --git a/gpxe/src/arch/i386/include/bits/nap.h b/gpxe/src/arch/i386/include/bits/nap.h
new file mode 100644
index 00000000..f8ba7a7c
--- /dev/null
+++ b/gpxe/src/arch/i386/include/bits/nap.h
@@ -0,0 +1,13 @@
+#ifndef _BITS_NAP_H
+#define _BITS_NAP_H
+
+/** @file
+ *
+ * i386-specific CPU sleeping API implementations
+ *
+ */
+
+#include <gpxe/bios_nap.h>
+#include <gpxe/efi/efix86_nap.h>
+
+#endif /* _BITS_MAP_H */
diff --git a/gpxe/src/arch/i386/include/bits/pci_io.h b/gpxe/src/arch/i386/include/bits/pci_io.h
new file mode 100644
index 00000000..0fbb439d
--- /dev/null
+++ b/gpxe/src/arch/i386/include/bits/pci_io.h
@@ -0,0 +1,13 @@
+#ifndef _BITS_PCI_IO_H
+#define _BITS_PCI_IO_H
+
+/** @file
+ *
+ * i386-specific PCI I/O API implementations
+ *
+ */
+
+#include <gpxe/pcibios.h>
+#include <gpxe/pcidirect.h>
+
+#endif /* _BITS_PCI_IO_H */
diff --git a/gpxe/src/arch/i386/include/bits/timer.h b/gpxe/src/arch/i386/include/bits/timer.h
new file mode 100644
index 00000000..99666d84
--- /dev/null
+++ b/gpxe/src/arch/i386/include/bits/timer.h
@@ -0,0 +1,13 @@
+#ifndef _BITS_TIMER_H
+#define _BITS_TIMER_H
+
+/** @file
+ *
+ * i386-specific timer API implementations
+ *
+ */
+
+#include <gpxe/bios_timer.h>
+#include <gpxe/rdtsc_timer.h>
+
+#endif /* _BITS_TIMER_H */
diff --git a/gpxe/src/arch/i386/include/bits/timer2.h b/gpxe/src/arch/i386/include/bits/timer2.h
deleted file mode 100644
index 83923b29..00000000
--- a/gpxe/src/arch/i386/include/bits/timer2.h
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef BITS_TIMER2_H
-#define BITS_TIMER2_H
-
-#include <stddef.h>
-
-void i386_timer2_udelay(unsigned int usecs);
-
-#endif
diff --git a/gpxe/src/arch/i386/include/bits/uaccess.h b/gpxe/src/arch/i386/include/bits/uaccess.h
index 9c6d0c21..0ecc5028 100644
--- a/gpxe/src/arch/i386/include/bits/uaccess.h
+++ b/gpxe/src/arch/i386/include/bits/uaccess.h
@@ -1,6 +1,12 @@
#ifndef _BITS_UACCESS_H
#define _BITS_UACCESS_H
-#include <realmode.h>
+/** @file
+ *
+ * i386-specific user access API implementations
+ *
+ */
+
+#include <librm.h>
#endif /* _BITS_UACCESS_H */
diff --git a/gpxe/src/arch/i386/include/bits/umalloc.h b/gpxe/src/arch/i386/include/bits/umalloc.h
new file mode 100644
index 00000000..dcbd0a6b
--- /dev/null
+++ b/gpxe/src/arch/i386/include/bits/umalloc.h
@@ -0,0 +1,12 @@
+#ifndef _BITS_UMALLOC_H
+#define _BITS_UMALLOC_H
+
+/** @file
+ *
+ * i386-specific user memory allocation API implementations
+ *
+ */
+
+#include <gpxe/memtop_umalloc.h>
+
+#endif /* _BITS_UMALLOC_H */
diff --git a/gpxe/src/arch/i386/include/gpxe/bios_nap.h b/gpxe/src/arch/i386/include/gpxe/bios_nap.h
new file mode 100644
index 00000000..f1c721e9
--- /dev/null
+++ b/gpxe/src/arch/i386/include/gpxe/bios_nap.h
@@ -0,0 +1,16 @@
+#ifndef _GPXE_BIOS_NAP_H
+#define _GPXE_BIOS_NAP_H
+
+/** @file
+ *
+ * BIOS CPU sleeping
+ *
+ */
+
+#ifdef NAP_PCBIOS
+#define NAP_PREFIX_pcbios
+#else
+#define NAP_PREFIX_pcbios __pcbios_
+#endif
+
+#endif /* _GPXE_BIOS_NAP_H */
diff --git a/gpxe/src/arch/i386/include/gpxe/bios_timer.h b/gpxe/src/arch/i386/include/gpxe/bios_timer.h
new file mode 100644
index 00000000..7e3caa3c
--- /dev/null
+++ b/gpxe/src/arch/i386/include/gpxe/bios_timer.h
@@ -0,0 +1,42 @@
+#ifndef _GPXE_BIOS_TIMER_H
+#define _GPXE_BIOS_TIMER_H
+
+/** @file
+ *
+ * BIOS timer
+ *
+ */
+
+#ifdef TIMER_PCBIOS
+#define TIMER_PREFIX_pcbios
+#else
+#define TIMER_PREFIX_pcbios __pcbios_
+#endif
+
+#include <gpxe/timer2.h>
+
+/**
+ * Delay for a fixed number of microseconds
+ *
+ * @v usecs Number of microseconds for which to delay
+ */
+static inline __always_inline void
+TIMER_INLINE ( pcbios, udelay ) ( unsigned long usecs ) {
+ /* BIOS timer is not high-resolution enough for udelay(), so
+ * we use timer2
+ */
+ timer2_udelay ( usecs );
+}
+
+/**
+ * Get number of ticks per second
+ *
+ * @ret ticks_per_sec Number of ticks per second
+ */
+static inline __always_inline unsigned long
+TIMER_INLINE ( pcbios, ticks_per_sec ) ( void ) {
+ /* BIOS timer ticks over at 18.2 ticks per second */
+ return 18;
+}
+
+#endif /* _GPXE_BIOS_TIMER_H */
diff --git a/gpxe/src/arch/i386/include/gpxe/efi/efix86_nap.h b/gpxe/src/arch/i386/include/gpxe/efi/efix86_nap.h
new file mode 100644
index 00000000..91424c54
--- /dev/null
+++ b/gpxe/src/arch/i386/include/gpxe/efi/efix86_nap.h
@@ -0,0 +1,16 @@
+#ifndef _GPXE_EFIX86_NAP_H
+#define _GPXE_EFIX86_NAP_H
+
+/** @file
+ *
+ * EFI CPU sleeping
+ *
+ */
+
+#ifdef NAP_EFIX86
+#define NAP_PREFIX_efix86
+#else
+#define NAP_PREFIX_efix86 __efix86_
+#endif
+
+#endif /* _GPXE_EFIX86_NAP_H */
diff --git a/gpxe/src/arch/i386/include/gpxe/memtop_umalloc.h b/gpxe/src/arch/i386/include/gpxe/memtop_umalloc.h
new file mode 100644
index 00000000..a3cd2c01
--- /dev/null
+++ b/gpxe/src/arch/i386/include/gpxe/memtop_umalloc.h
@@ -0,0 +1,16 @@
+#ifndef _GPXE_MEMTOP_UMALLOC_H
+#define _GPXE_MEMTOP_UMALLOC_H
+
+/** @file
+ *
+ * External memory allocation
+ *
+ */
+
+#ifdef UMALLOC_MEMTOP
+#define UMALLOC_PREFIX_memtop
+#else
+#define UMALLOC_PREFIX_memtop __memtop_
+#endif
+
+#endif /* _GPXE_MEMTOP_UMALLOC_H */
diff --git a/gpxe/src/arch/i386/include/pcibios.h b/gpxe/src/arch/i386/include/gpxe/pcibios.h
index 3d08d135..b86f5abd 100644
--- a/gpxe/src/arch/i386/include/pcibios.h
+++ b/gpxe/src/arch/i386/include/gpxe/pcibios.h
@@ -1,5 +1,5 @@
-#ifndef _PCIBIOS_H
-#define _PCIBIOS_H
+#ifndef _GPXE_PCIBIOS_H
+#define _GPXE_PCIBIOS_H
#include <stdint.h>
@@ -9,6 +9,12 @@
*
*/
+#ifdef PCIAPI_PCBIOS
+#define PCIAPI_PREFIX_pcbios
+#else
+#define PCIAPI_PREFIX_pcbios __pcbios_
+#endif
+
struct pci_device;
#define PCIBIOS_INSTALLATION_CHECK 0xb1010000
@@ -19,7 +25,6 @@ struct pci_device;
#define PCIBIOS_WRITE_CONFIG_WORD 0xb10c0000
#define PCIBIOS_WRITE_CONFIG_DWORD 0xb10d0000
-extern int pcibios_max_bus ( void );
extern int pcibios_read ( struct pci_device *pci, uint32_t command,
uint32_t *value );
extern int pcibios_write ( struct pci_device *pci, uint32_t command,
@@ -33,9 +38,10 @@ extern int pcibios_write ( struct pci_device *pci, uint32_t command,
* @v value Value read
* @ret rc Return status code
*/
-static inline __attribute__ (( always_inline )) int
-pcibios_read_config_byte ( struct pci_device *pci, unsigned int where,
- uint8_t *value ) {
+static inline __always_inline int
+PCIAPI_INLINE ( pcbios, pci_read_config_byte ) ( struct pci_device *pci,
+ unsigned int where,
+ uint8_t *value ) {
uint32_t tmp;
int rc;
@@ -52,9 +58,10 @@ pcibios_read_config_byte ( struct pci_device *pci, unsigned int where,
* @v value Value read
* @ret rc Return status code
*/
-static inline __attribute__ (( always_inline )) int
-pcibios_read_config_word ( struct pci_device *pci, unsigned int where,
- uint16_t *value ) {
+static inline __always_inline int
+PCIAPI_INLINE ( pcbios, pci_read_config_word ) ( struct pci_device *pci,
+ unsigned int where,
+ uint16_t *value ) {
uint32_t tmp;
int rc;
@@ -71,9 +78,10 @@ pcibios_read_config_word ( struct pci_device *pci, unsigned int where,
* @v value Value read
* @ret rc Return status code
*/
-static inline __attribute__ (( always_inline )) int
-pcibios_read_config_dword ( struct pci_device *pci, unsigned int where,
- uint32_t *value ) {
+static inline __always_inline int
+PCIAPI_INLINE ( pcbios, pci_read_config_dword ) ( struct pci_device *pci,
+ unsigned int where,
+ uint32_t *value ) {
return pcibios_read ( pci, PCIBIOS_READ_CONFIG_DWORD | where, value );
}
@@ -85,9 +93,10 @@ pcibios_read_config_dword ( struct pci_device *pci, unsigned int where,
* @v value Value to be written
* @ret rc Return status code
*/
-static inline __attribute__ (( always_inline )) int
-pcibios_write_config_byte ( struct pci_device *pci, unsigned int where,
- uint8_t value ) {
+static inline __always_inline int
+PCIAPI_INLINE ( pcbios, pci_write_config_byte ) ( struct pci_device *pci,
+ unsigned int where,
+ uint8_t value ) {
return pcibios_write ( pci, PCIBIOS_WRITE_CONFIG_BYTE | where, value );
}
@@ -99,9 +108,10 @@ pcibios_write_config_byte ( struct pci_device *pci, unsigned int where,
* @v value Value to be written
* @ret rc Return status code
*/
-static inline __attribute__ (( always_inline )) int
-pcibios_write_config_word ( struct pci_device *pci, unsigned int where,
- uint16_t value ) {
+static inline __always_inline int
+PCIAPI_INLINE ( pcbios, pci_write_config_word ) ( struct pci_device *pci,
+ unsigned int where,
+ uint16_t value ) {
return pcibios_write ( pci, PCIBIOS_WRITE_CONFIG_WORD | where, value );
}
@@ -113,10 +123,11 @@ pcibios_write_config_word ( struct pci_device *pci, unsigned int where,
* @v value Value to be written
* @ret rc Return status code
*/
-static inline __attribute__ (( always_inline )) int
-pcibios_write_config_dword ( struct pci_device *pci, unsigned int where,
- uint32_t value ) {
+static inline __always_inline int
+PCIAPI_INLINE ( pcbios, pci_write_config_dword ) ( struct pci_device *pci,
+ unsigned int where,
+ uint32_t value ) {
return pcibios_write ( pci, PCIBIOS_WRITE_CONFIG_DWORD | where, value);
}
-#endif /* _PCIBIOS_H */
+#endif /* _GPXE_PCIBIOS_H */
diff --git a/gpxe/src/arch/i386/include/pcidirect.h b/gpxe/src/arch/i386/include/gpxe/pcidirect.h
index 4e2e9d12..fe433c6f 100644
--- a/gpxe/src/arch/i386/include/pcidirect.h
+++ b/gpxe/src/arch/i386/include/gpxe/pcidirect.h
@@ -2,7 +2,13 @@
#define _PCIDIRECT_H
#include <stdint.h>
-#include <io.h>
+#include <gpxe/io.h>
+
+#ifdef PCIAPI_DIRECT
+#define PCIAPI_PREFIX_direct
+#else
+#define PCIAPI_PREFIX_direct __direct_
+#endif
/** @file
*
@@ -22,7 +28,8 @@ extern void pcidirect_prepare ( struct pci_device *pci, int where );
*
* @ret max_bus Maximum bus number
*/
-static inline int pcidirect_max_bus ( void ) {
+static inline __always_inline int
+PCIAPI_INLINE ( direct, pci_max_bus ) ( void ) {
/* No way to work this out via Type 1 accesses */
return 0xff;
}
@@ -35,9 +42,10 @@ static inline int pcidirect_max_bus ( void ) {
* @v value Value read
* @ret rc Return status code
*/
-static inline __attribute__ (( always_inline )) int
-pcidirect_read_config_byte ( struct pci_device *pci, unsigned int where,
- uint8_t *value ) {
+static inline __always_inline int
+PCIAPI_INLINE ( direct, pci_read_config_byte ) ( struct pci_device *pci,
+ unsigned int where,
+ uint8_t *value ) {
pcidirect_prepare ( pci, where );
*value = inb ( PCIDIRECT_CONFIG_DATA + ( where & 3 ) );
return 0;
@@ -51,9 +59,10 @@ pcidirect_read_config_byte ( struct pci_device *pci, unsigned int where,
* @v value Value read
* @ret rc Return status code
*/
-static inline __attribute__ (( always_inline )) int
-pcidirect_read_config_word ( struct pci_device *pci, unsigned int where,
- uint16_t *value ) {
+static inline __always_inline int
+PCIAPI_INLINE ( direct, pci_read_config_word ) ( struct pci_device *pci,
+ unsigned int where,
+ uint16_t *value ) {
pcidirect_prepare ( pci, where );
*value = inw ( PCIDIRECT_CONFIG_DATA + ( where & 2 ) );
return 0;
@@ -67,9 +76,10 @@ pcidirect_read_config_word ( struct pci_device *pci, unsigned int where,
* @v value Value read
* @ret rc Return status code
*/
-static inline __attribute__ (( always_inline )) int
-pcidirect_read_config_dword ( struct pci_device *pci, unsigned int where,
- uint32_t *value ) {
+static inline __always_inline int
+PCIAPI_INLINE ( direct, pci_read_config_dword ) ( struct pci_device *pci,
+ unsigned int where,
+ uint32_t *value ) {
pcidirect_prepare ( pci, where );
*value = inl ( PCIDIRECT_CONFIG_DATA );
return 0;
@@ -83,9 +93,10 @@ pcidirect_read_config_dword ( struct pci_device *pci, unsigned int where,
* @v value Value to be written
* @ret rc Return status code
*/
-static inline __attribute__ (( always_inline )) int
-pcidirect_write_config_byte ( struct pci_device *pci, unsigned int where,
- uint8_t value ) {
+static inline __always_inline int
+PCIAPI_INLINE ( direct, pci_write_config_byte ) ( struct pci_device *pci,
+ unsigned int where,
+ uint8_t value ) {
pcidirect_prepare ( pci, where );
outb ( value, PCIDIRECT_CONFIG_DATA + ( where & 3 ) );
return 0;
@@ -99,9 +110,10 @@ pcidirect_write_config_byte ( struct pci_device *pci, unsigned int where,
* @v value Value to be written
* @ret rc Return status code
*/
-static inline __attribute__ (( always_inline )) int
-pcidirect_write_config_word ( struct pci_device *pci, unsigned int where,
- uint16_t value ) {
+static inline __always_inline int
+PCIAPI_INLINE ( direct, pci_write_config_word ) ( struct pci_device *pci,
+ unsigned int where,
+ uint16_t value ) {
pcidirect_prepare ( pci, where );
outw ( value, PCIDIRECT_CONFIG_DATA + ( where & 2 ) );
return 0;
@@ -115,9 +127,10 @@ pcidirect_write_config_word ( struct pci_device *pci, unsigned int where,
* @v value Value to be written
* @ret rc Return status code
*/
-static inline __attribute__ (( always_inline )) int
-pcidirect_write_config_dword ( struct pci_device *pci, unsigned int where,
- uint32_t value ) {
+static inline __always_inline int
+PCIAPI_INLINE ( direct, pci_write_config_dword ) ( struct pci_device *pci,
+ unsigned int where,
+ uint32_t value ) {
pcidirect_prepare ( pci, where );
outl ( value, PCIDIRECT_CONFIG_DATA );
return 0;
diff --git a/gpxe/src/arch/i386/include/gpxe/rdtsc_timer.h b/gpxe/src/arch/i386/include/gpxe/rdtsc_timer.h
new file mode 100644
index 00000000..0e03d707
--- /dev/null
+++ b/gpxe/src/arch/i386/include/gpxe/rdtsc_timer.h
@@ -0,0 +1,37 @@
+#ifndef _GPXE_RDTSC_TIMER_H
+#define _GPXE_RDTSC_TIMER_H
+
+/** @file
+ *
+ * RDTSC timer
+ *
+ */
+
+#ifdef TIMER_RDTSC
+#define TIMER_PREFIX_rdtsc
+#else
+#define TIMER_PREFIX_rdtsc __rdtsc_
+#endif
+
+/**
+ * RDTSC values can easily overflow an unsigned long. We discard the
+ * low-order bits in order to obtain sensibly-scaled values.
+ */
+#define TSC_SHIFT 8
+
+/**
+ * Get current system time in ticks
+ *
+ * @ret ticks Current time, in ticks
+ */
+static inline __always_inline unsigned long
+TIMER_INLINE ( rdtsc, currticks ) ( void ) {
+ unsigned long ticks;
+
+ __asm__ __volatile__ ( "rdtsc\n\t"
+ "shrdl %1, %%edx, %%eax\n\t"
+ : "=a" ( ticks ) : "i" ( TSC_SHIFT ) : "edx" );
+ return ticks;
+}
+
+#endif /* _GPXE_RDTSC_TIMER_H */
diff --git a/gpxe/src/arch/i386/include/gpxe/timer2.h b/gpxe/src/arch/i386/include/gpxe/timer2.h
new file mode 100644
index 00000000..59705fa2
--- /dev/null
+++ b/gpxe/src/arch/i386/include/gpxe/timer2.h
@@ -0,0 +1,12 @@
+#ifndef _GPXE_TIMER2_H
+#define _GPXE_TIMER2_H
+
+/** @file
+ *
+ * Timer chip control
+ *
+ */
+
+extern void timer2_udelay ( unsigned long usecs );
+
+#endif /* _GPXE_TIMER2_H */
diff --git a/gpxe/src/arch/i386/include/gpxe/x86_io.h b/gpxe/src/arch/i386/include/gpxe/x86_io.h
new file mode 100644
index 00000000..b1ae3bac
--- /dev/null
+++ b/gpxe/src/arch/i386/include/gpxe/x86_io.h
@@ -0,0 +1,151 @@
+#ifndef _GPXE_X86_IO_H
+#define _GPXE_X86_IO_H
+
+/** @file
+ *
+ * gPXE I/O API for x86
+ *
+ * i386 uses direct pointer dereferences for accesses to memory-mapped
+ * I/O space, and the inX/outX instructions for accesses to
+ * port-mapped I/O space.
+ *
+ * 64-bit atomic accesses (readq() and writeq()) use MMX instructions,
+ * and will crash original Pentium and earlier CPUs. Fortunately, no
+ * hardware that requires atomic 64-bit accesses will physically fit
+ * into a machine with such an old CPU anyway.
+ */
+
+#ifdef IOAPI_X86
+#define IOAPI_PREFIX_x86
+#else
+#define IOAPI_PREFIX_x86 __x86_
+#endif
+
+/*
+ * Memory space mappings
+ *
+ */
+
+/*
+ * Physical<->Bus and Bus<->I/O address mappings
+ *
+ */
+
+static inline __always_inline unsigned long
+IOAPI_INLINE ( x86, phys_to_bus ) ( unsigned long phys_addr ) {
+ return phys_addr;
+}
+
+static inline __always_inline unsigned long
+IOAPI_INLINE ( x86, bus_to_phys ) ( unsigned long bus_addr ) {
+ return bus_addr;
+}
+
+static inline __always_inline void *
+IOAPI_INLINE ( x86, ioremap ) ( unsigned long bus_addr, size_t len __unused ) {
+ return phys_to_virt ( bus_addr );
+}
+
+static inline __always_inline void
+IOAPI_INLINE ( x86, iounmap ) ( volatile const void *io_addr __unused ) {
+ /* Nothing to do */
+}
+
+static inline __always_inline unsigned long
+IOAPI_INLINE ( x86, io_to_bus ) ( volatile const void *io_addr ) {
+ return virt_to_phys ( io_addr );
+}
+
+/*
+ * MMIO reads and writes up to 32 bits
+ *
+ */
+
+#define X86_READX( _api_func, _type ) \
+static inline __always_inline _type \
+IOAPI_INLINE ( x86, _api_func ) ( volatile _type *io_addr ) { \
+ return *io_addr; \
+}
+X86_READX ( readb, uint8_t );
+X86_READX ( readw, uint16_t );
+X86_READX ( readl, uint32_t );
+
+#define X86_WRITEX( _api_func, _type ) \
+static inline __always_inline void \
+IOAPI_INLINE ( x86, _api_func ) ( _type data, \
+ volatile _type *io_addr ) { \
+ *io_addr = data; \
+}
+X86_WRITEX ( writeb, uint8_t );
+X86_WRITEX ( writew, uint16_t );
+X86_WRITEX ( writel, uint32_t );
+
+/*
+ * PIO reads and writes up to 32 bits
+ *
+ */
+
+#define X86_INX( _insn_suffix, _type, _reg_prefix ) \
+static inline __always_inline _type \
+IOAPI_INLINE ( x86, in ## _insn_suffix ) ( volatile _type *io_addr ) { \
+ _type data; \
+ __asm__ __volatile__ ( "in" #_insn_suffix " %w1, %" _reg_prefix "0" \
+ : "=a" ( data ) : "Nd" ( io_addr ) ); \
+ return data; \
+} \
+static inline __always_inline void \
+IOAPI_INLINE ( x86, ins ## _insn_suffix ) ( volatile _type *io_addr, \
+ _type *data, \
+ unsigned int count ) { \
+ unsigned int discard_D; \
+ __asm__ __volatile__ ( "rep ins" #_insn_suffix \
+ : "=D" ( discard_D ) \
+ : "d" ( io_addr ), "c" ( count ), \
+ "0" ( data ) ); \
+}
+X86_INX ( b, uint8_t, "b" );
+X86_INX ( w, uint16_t, "w" );
+X86_INX ( l, uint32_t, "k" );
+
+#define X86_OUTX( _insn_suffix, _type, _reg_prefix ) \
+static inline __always_inline void \
+IOAPI_INLINE ( x86, out ## _insn_suffix ) ( _type data, \
+ volatile _type *io_addr ) { \
+ __asm__ __volatile__ ( "out" #_insn_suffix " %" _reg_prefix "0, %w1" \
+ : : "a" ( data ), "Nd" ( io_addr ) ); \
+} \
+static inline __always_inline void \
+IOAPI_INLINE ( x86, outs ## _insn_suffix ) ( volatile _type *io_addr, \
+ const _type *data, \
+ unsigned int count ) { \
+ unsigned int discard_S; \
+ __asm__ __volatile__ ( "rep outs" #_insn_suffix \
+ : "=S" ( discard_S ) \
+ : "d" ( io_addr ), "c" ( count ), \
+ "0" ( data ) ); \
+}
+X86_OUTX ( b, uint8_t, "b" );
+X86_OUTX ( w, uint16_t, "w" );
+X86_OUTX ( l, uint32_t, "k" );
+
+/*
+ * Slow down I/O
+ *
+ */
+
+static inline __always_inline void
+IOAPI_INLINE ( x86, iodelay ) ( void ) {
+ __asm__ __volatile__ ( "outb %al, $0x80" );
+}
+
+/*
+ * Memory barrier
+ *
+ */
+
+static inline __always_inline void
+IOAPI_INLINE ( x86, mb ) ( void ) {
+ __asm__ __volatile__ ( "lock; addl $0, 0(%%esp)" : : : "memory" );
+}
+
+#endif /* _GPXE_X86_IO_H */
diff --git a/gpxe/src/arch/i386/include/int13.h b/gpxe/src/arch/i386/include/int13.h
index 72ca97d7..bf6d0318 100644
--- a/gpxe/src/arch/i386/include/int13.h
+++ b/gpxe/src/arch/i386/include/int13.h
@@ -9,6 +9,7 @@
#include <stdint.h>
#include <gpxe/list.h>
+#include <realmode.h>
struct block_device;
diff --git a/gpxe/src/arch/i386/include/io.h b/gpxe/src/arch/i386/include/io.h
deleted file mode 100644
index c26fdf7e..00000000
--- a/gpxe/src/arch/i386/include/io.h
+++ /dev/null
@@ -1,265 +0,0 @@
-#ifndef ETHERBOOT_IO_H
-#define ETHERBOOT_IO_H
-
-#include <stdint.h>
-#include "virtaddr.h"
-
-/* virt_to_bus converts an addresss inside of etherboot [_start, _end]
- * into a memory access cards can use.
- */
-#define virt_to_bus virt_to_phys
-
-
-/* bus_to_virt reverses virt_to_bus, the address must be output
- * from virt_to_bus to be valid. This function does not work on
- * all bus addresses.
- */
-#define bus_to_virt phys_to_virt
-
-/* ioremap converts a random 32bit bus address into something
- * etherboot can access.
- */
-static inline void *ioremap(unsigned long bus_addr, unsigned long length __unused)
-{
- return bus_to_virt(bus_addr);
-}
-
-/* iounmap cleans up anything ioremap had to setup */
-static inline void iounmap(void *virt_addr __unused)
-{
- return;
-}
-
-/*
- * This file contains the definitions for the x86 IO instructions
- * inb/inw/inl/outb/outw/outl and the "string versions" of the same
- * (insb/insw/insl/outsb/outsw/outsl). You can also use "pausing"
- * versions of the single-IO instructions (inb_p/inw_p/..).
- *
- * This file is not meant to be obfuscating: it's just complicated
- * to (a) handle it all in a way that makes gcc able to optimize it
- * as well as possible and (b) trying to avoid writing the same thing
- * over and over again with slight variations and possibly making a
- * mistake somewhere.
- */
-
-/*
- * Thanks to James van Artsdalen for a better timing-fix than
- * the two short jumps: using outb's to a nonexistent port seems
- * to guarantee better timings even on fast machines.
- *
- * On the other hand, I'd like to be sure of a non-existent port:
- * I feel a bit unsafe about using 0x80 (should be safe, though)
- *
- * Linus
- */
-
-#ifdef SLOW_IO_BY_JUMPING
-#define __SLOW_DOWN_IO __asm__ __volatile__("jmp 1f\n1:\tjmp 1f\n1:")
-#else
-#define __SLOW_DOWN_IO __asm__ __volatile__("outb %al,$0x80")
-#endif
-
-#ifdef REALLY_SLOW_IO
-#define SLOW_DOWN_IO { __SLOW_DOWN_IO; __SLOW_DOWN_IO; __SLOW_DOWN_IO; __SLOW_DOWN_IO; }
-#else
-#define SLOW_DOWN_IO __SLOW_DOWN_IO
-#endif
-
-/*
- * readX/writeX() are used to access memory mapped devices. On some
- * architectures the memory mapped IO stuff needs to be accessed
- * differently. On the x86 architecture, we just read/write the
- * memory location directly.
- */
-static inline __attribute__ (( always_inline )) unsigned long
-_readb ( volatile uint8_t *addr ) {
- unsigned long data = *addr;
- DBGIO ( "[%08lx] => %02lx\n", virt_to_phys ( addr ), data );
- return data;
-}
-static inline __attribute__ (( always_inline )) unsigned long
-_readw ( volatile uint16_t *addr ) {
- unsigned long data = *addr;
- DBGIO ( "[%08lx] => %04lx\n", virt_to_phys ( addr ), data );
- return data;
-}
-static inline __attribute__ (( always_inline )) unsigned long
-_readl ( volatile uint32_t *addr ) {
- unsigned long data = *addr;
- DBGIO ( "[%08lx] => %08lx\n", virt_to_phys ( addr ), data );
- return data;
-}
-#define readb( addr ) _readb ( ( volatile uint8_t * ) (addr) )
-#define readw( addr ) _readw ( ( volatile uint16_t * ) (addr) )
-#define readl( addr ) _readl ( ( volatile uint32_t * ) (addr) )
-
-static inline __attribute__ (( always_inline )) void
-_writeb ( unsigned long data, volatile uint8_t *addr ) {
- DBGIO ( "[%08lx] <= %02lx\n", virt_to_phys ( addr ), data );
- *addr = data;
-}
-static inline __attribute__ (( always_inline )) void
-_writew ( unsigned long data, volatile uint16_t *addr ) {
- DBGIO ( "[%08lx] <= %04lx\n", virt_to_phys ( addr ), data );
- *addr = data;
-}
-static inline __attribute__ (( always_inline )) void
-_writel ( unsigned long data, volatile uint32_t *addr ) {
- DBGIO ( "[%08lx] <= %08lx\n", virt_to_phys ( addr ), data );
- *addr = data;
-}
-#define writeb( b, addr ) _writeb ( (b), ( volatile uint8_t * ) (addr) )
-#define writew( b, addr ) _writew ( (b), ( volatile uint16_t * ) (addr) )
-#define writel( b, addr ) _writel ( (b), ( volatile uint32_t * ) (addr) )
-
-#define memcpy_fromio(a,b,c) memcpy((a),(void *)(b),(c))
-#define memcpy_toio(a,b,c) memcpy((void *)(a),(b),(c))
-
-/*
- * Force strict CPU ordering.
- * And yes, this is required on UP too when we're talking
- * to devices.
- *
- * For now, "wmb()" doesn't actually do anything, as all
- * Intel CPU's follow what Intel calls a *Processor Order*,
- * in which all writes are seen in the program order even
- * outside the CPU.
- *
- * I expect future Intel CPU's to have a weaker ordering,
- * but I'd also expect them to finally get their act together
- * and add some real memory barriers if so.
- *
- * Some non intel clones support out of order store. wmb() ceases to be a
- * nop for these.
- */
-
-#define mb() __asm__ __volatile__ ("lock; addl $0,0(%%esp)": : :"memory")
-#define rmb() mb()
-#define wmb() mb();
-
-
-/*
- * Talk about misusing macros..
- */
-
-#define __OUT1(s,x) \
-extern void __out##s(unsigned x value, unsigned short port); \
-extern inline void __out##s(unsigned x value, unsigned short port) {
-
-#define __OUT2(s,s1,s2) \
-__asm__ __volatile__ ("out" #s " %" s1 "0,%" s2 "1"
-
-#define __OUT(s,s1,x) \
-__OUT1(s,x) __OUT2(s,s1,"w") : : "a" (value), "d" (port)); } \
-__OUT1(s##c,x) __OUT2(s,s1,"") : : "a" (value), "id" (port)); } \
-__OUT1(s##_p,x) __OUT2(s,s1,"w") : : "a" (value), "d" (port)); SLOW_DOWN_IO; } \
-__OUT1(s##c_p,x) __OUT2(s,s1,"") : : "a" (value), "id" (port)); SLOW_DOWN_IO; }
-
-#define __IN1(s,x) \
-extern unsigned x __in##s(unsigned short port); \
-extern inline unsigned x __in##s(unsigned short port) { unsigned x _v;
-
-#define __IN2(s,s1,s2) \
-__asm__ __volatile__ ("in" #s " %" s2 "1,%" s1 "0"
-
-#define __IN(s,s1,x,i...) \
-__IN1(s,x) __IN2(s,s1,"w") : "=a" (_v) : "d" (port) ,##i ); return _v; } \
-__IN1(s##c,x) __IN2(s,s1,"") : "=a" (_v) : "id" (port) ,##i ); return _v; } \
-__IN1(s##_p,x) __IN2(s,s1,"w") : "=a" (_v) : "d" (port) ,##i ); SLOW_DOWN_IO; return _v; } \
-__IN1(s##c_p,x) __IN2(s,s1,"") : "=a" (_v) : "id" (port) ,##i ); SLOW_DOWN_IO; return _v; }
-
-#define __INS(s) \
-extern void ins##s(unsigned short port, void * addr, unsigned long count); \
-extern inline void ins##s(unsigned short port, void * addr, unsigned long count) \
-{ __asm__ __volatile__ ("cld ; rep ; ins" #s \
-: "=D" (addr), "=c" (count) : "d" (port),"0" (addr),"1" (count)); }
-
-#define __OUTS(s) \
-extern void outs##s(unsigned short port, const void * addr, unsigned long count); \
-extern inline void outs##s(unsigned short port, const void * addr, unsigned long count) \
-{ __asm__ __volatile__ ("cld ; rep ; outs" #s \
-: "=S" (addr), "=c" (count) : "d" (port),"0" (addr),"1" (count)); }
-
-__IN(b,"", char)
-__IN(w,"",short)
-__IN(l,"", long)
-
-__OUT(b,"b",char)
-__OUT(w,"w",short)
-__OUT(l,,int)
-
-__INS(b)
-__INS(w)
-__INS(l)
-
-__OUTS(b)
-__OUTS(w)
-__OUTS(l)
-
-/*
- * Note that due to the way __builtin_constant_p() works, you
- * - can't use it inside a inline function (it will never be true)
- * - you don't have to worry about side effects within the __builtin..
- */
-#define outb(val,port) \
-((__builtin_constant_p((port)) && (port) < 256) ? \
- __outbc((val),(port)) : \
- __outb((val),(port)))
-
-#define inb(port) \
-((__builtin_constant_p((port)) && (port) < 256) ? \
- __inbc(port) : \
- __inb(port))
-
-#define outb_p(val,port) \
-((__builtin_constant_p((port)) && (port) < 256) ? \
- __outbc_p((val),(port)) : \
- __outb_p((val),(port)))
-
-#define inb_p(port) \
-((__builtin_constant_p((port)) && (port) < 256) ? \
- __inbc_p(port) : \
- __inb_p(port))
-
-#define outw(val,port) \
-((__builtin_constant_p((port)) && (port) < 256) ? \
- __outwc((val),(port)) : \
- __outw((val),(port)))
-
-#define inw(port) \
-((__builtin_constant_p((port)) && (port) < 256) ? \
- __inwc(port) : \
- __inw(port))
-
-#define outw_p(val,port) \
-((__builtin_constant_p((port)) && (port) < 256) ? \
- __outwc_p((val),(port)) : \
- __outw_p((val),(port)))
-
-#define inw_p(port) \
-((__builtin_constant_p((port)) && (port) < 256) ? \
- __inwc_p(port) : \
- __inw_p(port))
-
-#define outl(val,port) \
-((__builtin_constant_p((port)) && (port) < 256) ? \
- __outlc((val),(port)) : \
- __outl((val),(port)))
-
-#define inl(port) \
-((__builtin_constant_p((port)) && (port) < 256) ? \
- __inlc(port) : \
- __inl(port))
-
-#define outl_p(val,port) \
-((__builtin_constant_p((port)) && (port) < 256) ? \
- __outlc_p((val),(port)) : \
- __outl_p((val),(port)))
-
-#define inl_p(port) \
-((__builtin_constant_p((port)) && (port) < 256) ? \
- __inlc_p(port) : \
- __inl_p(port))
-
-#endif /* ETHERBOOT_IO_H */
diff --git a/gpxe/src/arch/i386/include/librm.h b/gpxe/src/arch/i386/include/librm.h
index 07a85c59..9eb2767a 100644..100755
--- a/gpxe/src/arch/i386/include/librm.h
+++ b/gpxe/src/arch/i386/include/librm.h
@@ -1,21 +1,109 @@
#ifndef LIBRM_H
#define LIBRM_H
-/* Drag in protected-mode segment selector values */
-#include "virtaddr.h"
-#include "realmode.h"
+/* Segment selectors as used in our protected-mode GDTs.
+ *
+ * Don't change these unless you really know what you're doing.
+ */
+
+#define VIRTUAL_CS 0x08
+#define VIRTUAL_DS 0x10
+#define PHYSICAL_CS 0x18
+#define PHYSICAL_DS 0x20
+#define REAL_CS 0x28
+#define REAL_DS 0x30
+#if 0
+#define LONG_CS 0x38
+#define LONG_DS 0x40
+#endif
#ifndef ASSEMBLY
-#include "stddef.h"
-#include "string.h"
+#ifdef UACCESS_LIBRM
+#define UACCESS_PREFIX_librm
+#else
+#define UACCESS_PREFIX_librm __librm_
+#endif
+
+/* Variables in librm.S */
+extern unsigned long virt_offset;
+
+/**
+ * Convert physical address to user pointer
+ *
+ * @v phys_addr Physical address
+ * @ret userptr User pointer
+ */
+static inline __always_inline userptr_t
+UACCESS_INLINE ( librm, phys_to_user ) ( unsigned long phys_addr ) {
+ return ( phys_addr - virt_offset );
+}
-/*
- * Data structures and type definitions
+/**
+ * Convert user buffer to physical address
+ *
+ * @v userptr User pointer
+ * @v offset Offset from user pointer
+ * @ret phys_addr Physical address
+ */
+static inline __always_inline unsigned long
+UACCESS_INLINE ( librm, user_to_phys ) ( userptr_t userptr, off_t offset ) {
+ return ( userptr + offset + virt_offset );
+}
+
+static inline __always_inline userptr_t
+UACCESS_INLINE ( librm, virt_to_user ) ( volatile const void *addr ) {
+ return trivial_virt_to_user ( addr );
+}
+
+static inline __always_inline void *
+UACCESS_INLINE ( librm, user_to_virt ) ( userptr_t userptr, off_t offset ) {
+ return trivial_user_to_virt ( userptr, offset );
+}
+
+static inline __always_inline userptr_t
+UACCESS_INLINE ( librm, userptr_add ) ( userptr_t userptr, off_t offset ) {
+ return trivial_userptr_add ( userptr, offset );
+}
+
+static inline __always_inline void
+UACCESS_INLINE ( librm, memcpy_user ) ( userptr_t dest, off_t dest_off,
+ userptr_t src, off_t src_off,
+ size_t len ) {
+ trivial_memcpy_user ( dest, dest_off, src, src_off, len );
+}
+
+static inline __always_inline void
+UACCESS_INLINE ( librm, memmove_user ) ( userptr_t dest, off_t dest_off,
+ userptr_t src, off_t src_off,
+ size_t len ) {
+ trivial_memmove_user ( dest, dest_off, src, src_off, len );
+}
+
+static inline __always_inline void
+UACCESS_INLINE ( librm, memset_user ) ( userptr_t buffer, off_t offset,
+ int c, size_t len ) {
+ trivial_memset_user ( buffer, offset, c, len );
+}
+
+static inline __always_inline size_t
+UACCESS_INLINE ( librm, strlen_user ) ( userptr_t buffer, off_t offset ) {
+ return trivial_strlen_user ( buffer, offset );
+}
+
+static inline __always_inline off_t
+UACCESS_INLINE ( librm, memchr_user ) ( userptr_t buffer, off_t offset,
+ int c, size_t len ) {
+ return trivial_memchr_user ( buffer, offset, c, len );
+}
+
+
+/******************************************************************************
+ *
+ * Access to variables in .data16 and .text16
*
*/
-/* Access to variables in .data16 and .text16 */
extern char *data16;
extern char *text16;
@@ -72,178 +160,6 @@ extern uint16_t __text16 ( rm_ds );
*/
extern void gateA20_set ( void );
-/*
- * librm_mgmt: functions for manipulating base memory and executing
- * real-mode code.
- *
- * Full API documentation for these functions is in realmode.h.
- *
- */
-
-/* Macro for obtaining a physical address from a segment:offset pair. */
-#define VIRTUAL(x,y) ( phys_to_virt ( ( ( x ) << 4 ) + ( y ) ) )
-
-/* Copy to/from base memory */
-static inline __attribute__ (( always_inline )) void
-copy_to_real_librm ( unsigned int dest_seg, unsigned int dest_off,
- void *src, size_t n ) {
- memcpy ( VIRTUAL ( dest_seg, dest_off ), src, n );
-}
-static inline __attribute__ (( always_inline )) void
-copy_from_real_librm ( void *dest, unsigned int src_seg,
- unsigned int src_off, size_t n ) {
- memcpy ( dest, VIRTUAL ( src_seg, src_off ), n );
-}
-#define put_real_librm( var, dest_seg, dest_off ) \
- do { \
- * ( ( typeof(var) * ) VIRTUAL ( dest_seg, dest_off ) ) = var; \
- } while ( 0 )
-#define get_real_librm( var, src_seg, src_off ) \
- do { \
- var = * ( ( typeof(var) * ) VIRTUAL ( src_seg, src_off ) ); \
- } while ( 0 )
-#define copy_to_real copy_to_real_librm
-#define copy_from_real copy_from_real_librm
-#define put_real put_real_librm
-#define get_real get_real_librm
-
-/**
- * A pointer to a user buffer
- *
- * Even though we could just use a void *, we use an intptr_t so that
- * attempts to use normal pointers show up as compiler warnings. Such
- * code is actually valid for librm, but not for libkir (i.e. under
- * KEEP_IT_REAL), so it's good to have the warnings even under librm.
- */
-typedef intptr_t userptr_t;
-
-/**
- * Add offset to user pointer
- *
- * @v ptr User pointer
- * @v offset Offset
- * @ret new_ptr New pointer value
- */
-static inline __attribute__ (( always_inline )) userptr_t
-userptr_add ( userptr_t ptr, off_t offset ) {
- return ( ptr + offset );
-}
-
-/**
- * Copy data to user buffer
- *
- * @v buffer User buffer
- * @v offset Offset within user buffer
- * @v src Source
- * @v len Length
- */
-static inline __attribute__ (( always_inline )) void
-copy_to_user ( userptr_t buffer, off_t offset, const void *src, size_t len ) {
- memcpy ( ( ( void * ) buffer + offset ), src, len );
-}
-
-/**
- * Copy data from user buffer
- *
- * @v dest Destination
- * @v buffer User buffer
- * @v offset Offset within user buffer
- * @v len Length
- */
-static inline __attribute__ (( always_inline )) void
-copy_from_user ( void *dest, userptr_t buffer, off_t offset, size_t len ) {
- memcpy ( dest, ( ( void * ) buffer + offset ), len );
-}
-
-/**
- * Copy data between user buffers
- *
- * @v dest Destination user buffer
- * @v dest_off Offset within destination buffer
- * @v src Source user buffer
- * @v src_off Offset within source buffer
- * @v len Length
- */
-static inline __attribute__ (( always_inline )) void
-memcpy_user ( userptr_t dest, off_t dest_off, userptr_t src, off_t src_off,
- size_t len ) {
- memcpy ( ( ( void * ) dest + dest_off ), ( ( void * ) src + src_off ),
- len );
-}
-
-/**
- * Copy data between user buffers, allowing for overlap
- *
- * @v dest Destination user buffer
- * @v dest_off Offset within destination buffer
- * @v src Source user buffer
- * @v src_off Offset within source buffer
- * @v len Length
- */
-static inline __attribute__ (( always_inline )) void
-memmove_user ( userptr_t dest, off_t dest_off, userptr_t src, off_t src_off,
- size_t len ) {
- memmove ( ( ( void * ) dest + dest_off ), ( ( void * ) src + src_off ),
- len );
-}
-
-/**
- * Fill user buffer with a constant byte
- *
- * @v buffer User buffer
- * @v offset Offset within buffer
- * @v c Constant byte with which to fill
- * @v len Length
- */
-static inline __attribute__ (( always_inline )) void
-memset_user ( userptr_t buffer, off_t offset, int c, size_t len ) {
- memset ( ( ( void * ) buffer + offset ), c, len );
-}
-
-/**
- * Find length of NUL-terminated string in user buffer
- *
- * @v buffer User buffer
- * @v offset Offset within buffer
- * @ret len Length of string (excluding NUL)
- */
-static inline __attribute__ (( always_inline )) size_t
-strlen_user ( userptr_t buffer, off_t offset ) {
- return strlen ( ( void * ) buffer + offset );
-}
-
-/**
- * Find character in user buffer
- *
- * @v buffer User buffer
- * @v offset Starting offset within buffer
- * @v c Character to search for
- * @v len Length of user buffer
- * @ret offset Offset of character, or <0 if not found
- */
-static inline __attribute__ (( always_inline )) off_t
-memchr_user ( userptr_t buffer, off_t offset, int c, size_t len ) {
- void *found;
-
- found = memchr ( ( ( void * ) buffer + offset ), c, len );
- return ( found ? ( found - ( void * ) buffer ) : -1 );
-}
-
-/**
- * Convert virtual address to user buffer
- *
- * @v virtual Virtual address
- * @ret buffer User buffer
- *
- * This constructs a user buffer from an ordinary pointer. Use it
- * when you need to pass a pointer to an internal buffer to a function
- * that expects a @c userptr_t.
- */
-static inline __attribute__ (( always_inline )) userptr_t
-virt_to_user ( void * virtual ) {
- return ( ( intptr_t ) virtual );
-}
-
/**
* Convert segment:offset address to user buffer
*
@@ -251,32 +167,9 @@ virt_to_user ( void * virtual ) {
* @v offset Real-mode offset
* @ret buffer User buffer
*/
-static inline __attribute__ (( always_inline )) userptr_t
+static inline __always_inline userptr_t
real_to_user ( unsigned int segment, unsigned int offset ) {
- return virt_to_user ( VIRTUAL ( segment, offset ) );
-}
-
-/**
- * Convert physical address to user buffer
- *
- * @v physical Physical address
- * @ret buffer User buffer
- */
-static inline __attribute__ (( always_inline )) userptr_t
-phys_to_user ( physaddr_t physical ) {
- return virt_to_user ( phys_to_virt ( physical ) );
-}
-
-/**
- * Convert user buffer to physical address
- *
- * @v buffer User buffer
- * @v offset Offset within user buffer
- * @ret physical Physical address
- */
-static inline __attribute__ (( always_inline )) physaddr_t
-user_to_phys ( userptr_t buffer, off_t offset ) {
- return virt_to_phys ( ( void * ) buffer + offset );
+ return ( phys_to_user ( ( segment << 4 ) + offset ) );
}
extern uint16_t copy_user_to_rm_stack ( userptr_t data, size_t size );
diff --git a/gpxe/src/arch/i386/include/pci_io.h b/gpxe/src/arch/i386/include/pci_io.h
deleted file mode 100644
index 4888d557..00000000
--- a/gpxe/src/arch/i386/include/pci_io.h
+++ /dev/null
@@ -1,35 +0,0 @@
-#ifndef _PCI_IO_H
-#define _PCI_IO_H
-
-#include <pcibios.h>
-#include <pcidirect.h>
-
-/** @file
- *
- * i386 PCI configuration space access
- *
- * We have two methods of PCI configuration space access: the PCI BIOS
- * and direct Type 1 accesses. Selecting between them is via the
- * compile-time switch -DCONFIG_PCI_DIRECT.
- *
- */
-
-#if CONFIG_PCI_DIRECT
-#define pci_max_bus pcidirect_max_bus
-#define pci_read_config_byte pcidirect_read_config_byte
-#define pci_read_config_word pcidirect_read_config_word
-#define pci_read_config_dword pcidirect_read_config_dword
-#define pci_write_config_byte pcidirect_write_config_byte
-#define pci_write_config_word pcidirect_write_config_word
-#define pci_write_config_dword pcidirect_write_config_dword
-#else /* CONFIG_PCI_DIRECT */
-#define pci_max_bus pcibios_max_bus
-#define pci_read_config_byte pcibios_read_config_byte
-#define pci_read_config_word pcibios_read_config_word
-#define pci_read_config_dword pcibios_read_config_dword
-#define pci_write_config_byte pcibios_write_config_byte
-#define pci_write_config_word pcibios_write_config_word
-#define pci_write_config_dword pcibios_write_config_dword
-#endif /* CONFIG_PCI_DIRECT */
-
-#endif /* _PCI_IO_H */
diff --git a/gpxe/src/arch/i386/include/pxe_addr.h b/gpxe/src/arch/i386/include/pxe_addr.h
deleted file mode 100644
index 954551e8..00000000
--- a/gpxe/src/arch/i386/include/pxe_addr.h
+++ /dev/null
@@ -1,17 +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_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/gpxe/src/arch/i386/include/realmode.h b/gpxe/src/arch/i386/include/realmode.h
index 5d3ddf50..26e6dd77 100644
--- a/gpxe/src/arch/i386/include/realmode.h
+++ b/gpxe/src/arch/i386/include/realmode.h
@@ -1,45 +1,15 @@
#ifndef REALMODE_H
#define REALMODE_H
-#ifndef ASSEMBLY
-
-#include "stdint.h"
-#include "registers.h"
-#include "io.h"
+#include <stdint.h>
+#include <registers.h>
+#include <gpxe/uaccess.h>
/*
* Data structures and type definitions
*
*/
-/* Segment:offset structure. Note that the order within the structure
- * is offset:segment.
- */
-struct segoff {
- uint16_t offset;
- uint16_t segment;
-} __attribute__ (( packed ));
-
-typedef struct segoff segoff_t;
-
-/* Macro hackery needed to stringify bits of inline assembly */
-#define RM_XSTR(x) #x
-#define RM_STR(x) RM_XSTR(x)
-
-/* Drag in the selected real-mode transition library header */
-#ifdef KEEP_IT_REAL
-#include "libkir.h"
-#else
-#include "librm.h"
-#endif
-
-/*
- * The API to some functions is identical between librm and libkir, so
- * they are documented here, even though the prototypes are in librm.h
- * and libkir.h.
- *
- */
-
/*
* Declaration of variables in .data16
*
@@ -92,24 +62,53 @@ typedef struct segoff segoff_t;
* assembler output to make sure that it's doing the right thing.
*/
-/*
- * void copy_to_real ( uint16_t dest_seg, uint16_t dest_off,
- * void *src, size_t n )
- * void copy_from_real ( void *dest, uint16_t src_seg, uint16_t src_off,
- * size_t n )
+/**
+ * Copy data to base memory
*
- * These functions can be used to copy data to and from arbitrary
- * locations in base memory.
+ * @v dest_seg Destination segment
+ * @v dest_off Destination offset
+ * @v src Source
+ * @v len Length
*/
+static inline __always_inline void
+copy_to_real ( unsigned int dest_seg, unsigned int dest_off,
+ void *src, size_t n ) {
+ copy_to_user ( real_to_user ( dest_seg, dest_off ), 0, src, n );
+}
-/*
- * put_real ( variable, uint16_t dest_seg, uint16_t dest_off )
- * get_real ( variable, uint16_t src_seg, uint16_t src_off )
+/**
+ * Copy data to base memory
+ *
+ * @v dest Destination
+ * @v src_seg Source segment
+ * @v src_off Source offset
+ * @v len Length
+ */
+static inline __always_inline void
+copy_from_real ( void *dest, unsigned int src_seg,
+ unsigned int src_off, size_t n ) {
+ copy_from_user ( dest, real_to_user ( src_seg, src_off ), 0, n );
+}
+
+/**
+ * Write a single variable to base memory
*
- * These macros can be used to read or write single variables to and
- * from arbitrary locations in base memory. "variable" must be a
- * variable of either 1, 2 or 4 bytes in length.
+ * @v var Variable to write
+ * @v dest_seg Destination segment
+ * @v dest_off Destination offset
*/
+#define put_real( var, dest_seg, dest_off ) \
+ copy_to_real ( (dest_seg), (dest_off), &(var), sizeof (var) )
+
+/**
+ * Read a single variable from base memory
+ *
+ * @v var Variable to read
+ * @v src_seg Source segment
+ * @v src_off Source offset
+ */
+#define get_real( var, src_seg, src_off ) \
+ copy_from_real ( &(var), (src_seg), (src_off), sizeof (var) )
/*
* REAL_CODE ( asm_code_str )
@@ -123,6 +122,4 @@ typedef struct segoff segoff_t;
*
*/
-#endif /* ASSEMBLY */
-
#endif /* REALMODE_H */
diff --git a/gpxe/src/arch/i386/include/registers.h b/gpxe/src/arch/i386/include/registers.h
index 2b9b2b43..e68fa85a 100644
--- a/gpxe/src/arch/i386/include/registers.h
+++ b/gpxe/src/arch/i386/include/registers.h
@@ -10,8 +10,7 @@
*
*/
-#include "compiler.h" /* for doxygen */
-#include "stdint.h"
+#include <stdint.h>
/**
* A 16-bit general register.
@@ -184,4 +183,14 @@ struct i386_all_regs {
#define SF ( 1 << 7 )
#define OF ( 1 << 11 )
+/* Segment:offset structure. Note that the order within the structure
+ * is offset:segment.
+ */
+struct segoff {
+ uint16_t offset;
+ uint16_t segment;
+} PACKED;
+
+typedef struct segoff segoff_t;
+
#endif /* REGISTERS_H */
diff --git a/gpxe/src/arch/i386/include/undi.h b/gpxe/src/arch/i386/include/undi.h
index 9936e17f..c6253d0a 100644
--- a/gpxe/src/arch/i386/include/undi.h
+++ b/gpxe/src/arch/i386/include/undi.h
@@ -24,10 +24,6 @@ struct undi_device {
SEGOFF16_t ppxe;
/** Entry point */
SEGOFF16_t entry;
- /** Return stack */
- UINT16_t return_stack[3];
- /** Return type */
- UINT16_t return_type;
/** Free base memory after load */
UINT16_t fbms;
/** Free base memory prior to load */
@@ -99,4 +95,10 @@ static inline void * undi_get_drvdata ( struct undi_device *undi ) {
/** UNDI flag: START_UNDI has been called */
#define UNDI_FL_STARTED 0x0001
+/** UNDI flag: UNDI_STARTUP and UNDI_INITIALIZE have been called */
+#define UNDI_FL_INITIALIZED 0x0002
+
+/** UNDI flag: keep stack resident */
+#define UNDI_FL_KEEP_ALL 0x0004
+
#endif /* _UNDI_H */
diff --git a/gpxe/src/arch/i386/include/virtaddr.h b/gpxe/src/arch/i386/include/virtaddr.h
deleted file mode 100644
index f2ffa2a1..00000000
--- a/gpxe/src/arch/i386/include/virtaddr.h
+++ /dev/null
@@ -1,105 +0,0 @@
-#ifndef VIRTADDR_H
-#define VIRTADDR_H
-
-/* Segment selectors as used in our protected-mode GDTs.
- *
- * Don't change these unless you really know what you're doing.
- */
-
-#define VIRTUAL_CS 0x08
-#define VIRTUAL_DS 0x10
-#define PHYSICAL_CS 0x18
-#define PHYSICAL_DS 0x20
-#define REAL_CS 0x28
-#define REAL_DS 0x30
-#if 0
-#define LONG_CS 0x38
-#define LONG_DS 0x40
-#endif
-
-#ifndef ASSEMBLY
-
-#include "stdint.h"
-#include "string.h"
-
-#ifndef KEEP_IT_REAL
-
-/*
- * Without -DKEEP_IT_REAL, we are in 32-bit protected mode with a
- * fixed link address but an unknown physical start address. Our GDT
- * sets up code and data segments with an offset of virt_offset, so
- * that link-time addresses can still work.
- *
- */
-
-/* C-callable function prototypes */
-
-extern void relocate_to ( uint32_t new_phys_addr );
-
-/* Variables in virtaddr.S */
-extern unsigned long virt_offset;
-
-/*
- * Convert between virtual and physical addresses
- *
- */
-static inline unsigned long virt_to_phys ( volatile const void *virt_addr ) {
- return ( ( unsigned long ) virt_addr ) + virt_offset;
-}
-
-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, const void *src,
- size_t len ) {
- memcpy ( phys_to_virt ( dest ), src, len );
-}
-
-static inline void copy_from_phys ( void *dest, physaddr_t src, size_t len ) {
- memcpy ( dest, phys_to_virt ( src ), len );
-}
-
-static inline void copy_phys_to_phys ( physaddr_t dest, physaddr_t src,
- size_t len ) {
- memcpy ( phys_to_virt ( dest ), phys_to_virt ( src ), len );
-}
-
-#else /* KEEP_IT_REAL */
-
-/*
- * With -DKEEP_IT_REAL, we are in 16-bit real mode with fixed link
- * addresses and a segmented memory model. We have separate code and
- * data segments.
- *
- * Because we may be called in 16-bit protected mode (damn PXE spec),
- * we cannot simply assume that physical = segment * 16 + offset.
- * Instead, we have to look up the physical start address of the
- * segment in the !PXE structure. We have to assume that
- * virt_to_phys() is called only on pointers within the data segment,
- * because nothing passes segment information to us.
- *
- * We don't implement phys_to_virt at all, because there will be many
- * addresses that simply cannot be reached via a virtual address when
- * the virtual address space is limited to 64kB!
- */
-
-static inline unsigned long virt_to_phys ( volatile const void *virt_addr ) {
- /* Cheat: just for now, do the segment*16+offset calculation */
- uint16_t ds;
-
- __asm__ ( "movw %%ds, %%ax" : "=a" ( ds ) : );
- return ( 16 * ds + ( ( unsigned long ) virt_addr ) );
-}
-
-/* Define it as a deprecated function so that we get compile-time
- * warnings, rather than just the link-time errors.
- */
-extern void * phys_to_virt ( unsigned long phys_addr )
- __attribute__ ((deprecated));
-
-#endif /* KEEP_IT_REAL */
-
-#endif /* ASSEMBLY */
-
-#endif /* VIRTADDR_H */
diff --git a/gpxe/src/arch/i386/interface/efi/efix86_nap.c b/gpxe/src/arch/i386/interface/efi/efix86_nap.c
new file mode 100644
index 00000000..45e99a68
--- /dev/null
+++ b/gpxe/src/arch/i386/interface/efi/efix86_nap.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2008 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 <gpxe/nap.h>
+#include <gpxe/efi/efi.h>
+
+/** @file
+ *
+ * gPXE CPU sleeping API for EFI
+ *
+ */
+
+/**
+ * Sleep until next interrupt
+ *
+ */
+static void efix86_cpu_nap ( void ) {
+ /*
+ * I can't find any EFI API that allows us to put the CPU to
+ * sleep. The CpuSleep() function is defined in CpuLib.h, but
+ * isn't part of any exposed protocol so we have no way to
+ * call it.
+ *
+ * The EFI shell doesn't seem to bother sleeping the CPU; it
+ * just sits there idly burning power.
+ *
+ */
+ __asm__ __volatile__ ( "hlt" );
+}
+
+PROVIDE_NAP ( efix86, cpu_nap, efix86_cpu_nap );
diff --git a/gpxe/src/arch/i386/interface/pcbios/bios_nap.c b/gpxe/src/arch/i386/interface/pcbios/bios_nap.c
new file mode 100644
index 00000000..2f4a0513
--- /dev/null
+++ b/gpxe/src/arch/i386/interface/pcbios/bios_nap.c
@@ -0,0 +1,14 @@
+#include <gpxe/nap.h>
+#include <realmode.h>
+
+/**
+ * Save power by halting the CPU until the next interrupt
+ *
+ */
+static void bios_cpu_nap ( void ) {
+ __asm__ __volatile__ ( REAL_CODE ( "sti\n\t"
+ "hlt\n\t"
+ "cli\n\t" ) : : );
+}
+
+PROVIDE_NAP ( pcbios, cpu_nap, bios_cpu_nap );
diff --git a/gpxe/src/arch/i386/interface/pcbios/bios_timer.c b/gpxe/src/arch/i386/interface/pcbios/bios_timer.c
new file mode 100644
index 00000000..0b475ea3
--- /dev/null
+++ b/gpxe/src/arch/i386/interface/pcbios/bios_timer.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2008 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.
+ */
+
+/** @file
+ *
+ * BIOS timer
+ *
+ */
+
+#include <gpxe/timer.h>
+#include <realmode.h>
+#include <bios.h>
+
+/**
+ * Get current system time in ticks
+ *
+ * @ret ticks Current time, in ticks
+ *
+ * Use direct memory access to BIOS variables, longword 0040:006C
+ * (ticks today) and byte 0040:0070 (midnight crossover flag) instead
+ * of calling timeofday BIOS interrupt.
+ */
+static unsigned long bios_currticks ( void ) {
+ static int days = 0;
+ uint32_t ticks;
+ uint8_t midnight;
+
+ /* Re-enable interrupts so that the timer interrupt can occur */
+ __asm__ __volatile__ ( REAL_CODE ( "sti\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ "cli\n\t" ) : : );
+
+ get_real ( ticks, BDA_SEG, 0x006c );
+ get_real ( midnight, BDA_SEG, 0x0070 );
+
+ if ( midnight ) {
+ midnight = 0;
+ put_real ( midnight, BDA_SEG, 0x0070 );
+ days += 0x1800b0;
+ }
+
+ return ( days + ticks );
+}
+
+PROVIDE_TIMER_INLINE ( pcbios, udelay );
+PROVIDE_TIMER ( pcbios, currticks, bios_currticks );
+PROVIDE_TIMER_INLINE ( pcbios, ticks_per_sec );
diff --git a/gpxe/src/arch/i386/interface/pcbios/biosint.c b/gpxe/src/arch/i386/interface/pcbios/biosint.c
index 8ef2d7ab..1306f918 100644
--- a/gpxe/src/arch/i386/interface/pcbios/biosint.c
+++ b/gpxe/src/arch/i386/interface/pcbios/biosint.c
@@ -8,17 +8,6 @@
*/
/**
- * Hooked interrupt count
- *
- * At exit, after unhooking all possible interrupts, this counter
- * should be examined. If it is non-zero, it means that we failed to
- * unhook at least one interrupt vector, and so must not free up the
- * memory we are using. (Note that this also implies that we should
- * re-hook INT 15 in order to hide ourselves from the memory map).
- */
-int hooked_bios_interrupts = 0;
-
-/**
* Hook INT vector
*
* @v interrupt INT number
diff --git a/gpxe/src/arch/i386/core/umalloc.c b/gpxe/src/arch/i386/interface/pcbios/memtop_umalloc.c
index 3990488c..2eb7f76d 100644
--- a/gpxe/src/arch/i386/core/umalloc.c
+++ b/gpxe/src/arch/i386/interface/pcbios/memtop_umalloc.c
@@ -36,9 +36,6 @@
/** Equivalent of NOWHERE for user pointers */
#define UNOWHERE ( ~UNULL )
-/** Start of Etherboot text, as defined by the linker */
-extern char _text[];
-
/** An external memory block */
struct external_memory {
/** Size of this memory block (excluding this header) */
@@ -135,7 +132,7 @@ static void ecollect_free ( void ) {
* Calling realloc() with a new size of zero is a valid way to free a
* memory block.
*/
-userptr_t urealloc ( userptr_t ptr, size_t new_size ) {
+static userptr_t memtop_urealloc ( userptr_t ptr, size_t new_size ) {
struct external_memory extmem;
userptr_t new = ptr;
size_t align;
@@ -200,25 +197,4 @@ userptr_t urealloc ( userptr_t ptr, size_t new_size ) {
return ( new_size ? new : UNOWHERE );
}
-/**
- * Allocate external memory
- *
- * @v size Requested size
- * @ret ptr Memory, or UNULL
- *
- * Memory is guaranteed to be aligned to a page boundary.
- */
-userptr_t umalloc ( size_t size ) {
- return urealloc ( UNULL, size );
-}
-
-/**
- * Free external memory
- *
- * @v ptr Memory allocated by umalloc(), or UNULL
- *
- * If @c ptr is UNULL, no action is taken.
- */
-void ufree ( userptr_t ptr ) {
- urealloc ( ptr, 0 );
-}
+PROVIDE_UMALLOC ( memtop, urealloc, memtop_urealloc );
diff --git a/gpxe/src/arch/i386/core/pcibios.c b/gpxe/src/arch/i386/interface/pcbios/pcibios.c
index 1c93e4be..81b4fd3c 100644
--- a/gpxe/src/arch/i386/core/pcibios.c
+++ b/gpxe/src/arch/i386/interface/pcbios/pcibios.c
@@ -18,7 +18,6 @@
#include <stdint.h>
#include <gpxe/pci.h>
-#include <pcibios.h>
#include <realmode.h>
/** @file
@@ -32,7 +31,7 @@
*
* @ret max_bus Maximum bus number
*/
-int pcibios_max_bus ( void ) {
+static int pcibios_max_bus ( void ) {
int discard_a, discard_D;
uint8_t max_bus;
@@ -104,3 +103,11 @@ int pcibios_write ( struct pci_device *pci, uint32_t command, uint32_t value ){
return ( ( status >> 8 ) & 0xff );
}
+
+PROVIDE_PCIAPI ( pcbios, pci_max_bus, pcibios_max_bus );
+PROVIDE_PCIAPI_INLINE ( pcbios, pci_read_config_byte );
+PROVIDE_PCIAPI_INLINE ( pcbios, pci_read_config_word );
+PROVIDE_PCIAPI_INLINE ( pcbios, pci_read_config_dword );
+PROVIDE_PCIAPI_INLINE ( pcbios, pci_write_config_byte );
+PROVIDE_PCIAPI_INLINE ( pcbios, pci_write_config_word );
+PROVIDE_PCIAPI_INLINE ( pcbios, pci_write_config_dword );
diff --git a/gpxe/src/arch/i386/interface/pxe/pxe_entry.S b/gpxe/src/arch/i386/interface/pxe/pxe_entry.S
index e5d327a5..8dd1a2ea 100644
--- a/gpxe/src/arch/i386/interface/pxe/pxe_entry.S
+++ b/gpxe/src/arch/i386/interface/pxe/pxe_entry.S
@@ -44,10 +44,10 @@ ppxe:
.byte SegDescCnt /* SegDescCnt */
.word 0 /* FirstSelector */
pxe_segments:
- .word 0, 0, 0, _data16_size /* Stack */
- .word 0, 0, 0, _data16_size /* UNDIData */
- .word 0, 0, 0, _text16_size /* UNDICode */
- .word 0, 0, 0, _text16_size /* UNDICodeWrite */
+ .word 0, 0, 0, _data16_memsz /* Stack */
+ .word 0, 0, 0, _data16_memsz /* UNDIData */
+ .word 0, 0, 0, _text16_memsz /* UNDICode */
+ .word 0, 0, 0, _text16_memsz /* UNDICodeWrite */
.word 0, 0, 0, 0 /* BC_Data */
.word 0, 0, 0, 0 /* BC_Code */
.word 0, 0, 0, 0 /* BC_CodeWrite */
@@ -76,15 +76,15 @@ pxenv:
.long 0 /* PMEntry */
.word 0 /* PMSelector */
.word 0 /* StackSeg */
- .word _data16_size /* StackSize */
+ .word _data16_memsz /* StackSize */
.word 0 /* BC_CodeSeg */
.word 0 /* BC_CodeSize */
.word 0 /* BC_DataSeg */
.word 0 /* BC_DataSize */
.word 0 /* UNDIDataSeg */
- .word _data16_size /* UNDIDataSize */
+ .word _data16_memsz /* UNDIDataSize */
.word 0 /* UNDICodeSeg */
- .word _text16_size /* UNDICodeSize */
+ .word _text16_memsz /* UNDICodeSize */
.word ppxe, 0 /* PXEPtr */
.equ pxenv_length, . - pxenv
.size pxenv, . - pxenv
diff --git a/gpxe/src/arch/i386/prefix/dskprefix.S b/gpxe/src/arch/i386/prefix/dskprefix.S
index cdc43b37..0156812a 100644
--- a/gpxe/src/arch/i386/prefix/dskprefix.S
+++ b/gpxe/src/arch/i386/prefix/dskprefix.S
@@ -144,8 +144,8 @@ got_sectors:
/* Jump to loaded copy */
ljmp $SYSSEG, $start_runtime
-endseg: .word SYSSEG + _load_size_pgh
- .section ".zinfo.fixup", "a" /* Compressor fixup information */
+endseg: .word SYSSEG + _filesz_pgh
+ .section ".zinfo.fixup", "a", @progbits /* Compressor fixups */
.ascii "SUBW"
.long endseg
.long 16
@@ -353,6 +353,7 @@ msg1end:
.word 0xAA55
start_runtime:
+ /* Install gPXE */
call install
/* Set up real-mode stack */
@@ -368,7 +369,10 @@ start_runtime:
pushl $main
pushw %cs
call prot_call
- popl %eax /* discard */
+ popl %ecx /* discard */
+
+ /* Uninstall gPXE */
+ call uninstall
/* Boot next device */
int $0x18
diff --git a/gpxe/src/arch/i386/prefix/efiprefix.S b/gpxe/src/arch/i386/prefix/efiprefix.S
new file mode 100644
index 00000000..c4cf68e4
--- /dev/null
+++ b/gpxe/src/arch/i386/prefix/efiprefix.S
@@ -0,0 +1,175 @@
+ .text
+ .code32
+ .arch i386
+ .section ".prefix", "a", @progbits
+ .org 0x00
+
+ /* DOS (.com) header
+ *
+ * EFI executables seem to leave most of this empty
+ */
+mzhdr:
+ .ascii "MZ" /* Magic number */
+ .word 0 /* Bytes on last page of file */
+ .word 0 /* Pages in file */
+ .word 0 /* Relocations */
+ .word 0 /* Size of header in paragraphs */
+ .word 0 /* Minimum extra paragraphs needed */
+ .word 0 /* Maximum extra paragraphs needed */
+ .word 0 /* Initial (relative) SS value */
+ .word 0 /* Initial SP value */
+ .word 0 /* "Checksum" */
+ .word 0 /* Initial IP value */
+ .word 0 /* Initial (relative) CS value */
+ .word 0 /* File address of relocation table */
+ .word 0 /* Ovesrlay number */
+ .word 0, 0, 0, 0 /* Reserved words */
+ .word 0 /* OEM identifier (for e_oeminfo) */
+ .word 0 /* OEM information; e_oemid specific */
+ .word 0, 0, 0, 0, 0 /* Reserved words */
+ .word 0, 0, 0, 0, 0 /* Reserved words */
+ .long pehdr_lma /* File address of new exe header */
+ .size mzhdr, . - mzhdr
+
+ /* PE header */
+ .org 0xc0 /* For compatibility with MS toolchain */
+pehdr:
+ .ascii "PE\0\0" /* Magic number */
+ .word 0x014c /* CPU architecture: i386 */
+ .word num_pe_sections /* Number of sections */
+ .long 0x10d1a884 /* Timestamp */
+ .long 0 /* Symbol table */
+ .long 0 /* Number of symbols */
+ .word opthdr_size /* Size of optional header */
+ .word 0x2102 /* Characteristics */
+ .size pehdr, . - pehdr
+ .equ pehdr_lma, pehdr - mzhdr
+
+ /* "Optional" header */
+opthdr:
+ .word 0x010b /* Magic number */
+ .byte 0 /* Linker major version number */
+ .byte 0 /* Linker minor version number */
+ .long _text_filesz /* Size of text section */
+ .long _data_filesz /* Size of data section */
+ .long _bss_filesz /* Size of bss section */
+ .long efi_entry_lma /* Entry point */
+ .long _text_lma /* Text section start RVA */
+ .long _data_lma /* Data section start RVA */
+ .long 0 /* Image base address */
+ .long _max_align /* Section alignment */
+ .long _max_align /* File alignment */
+ .word 0 /* Operating system major version number */
+ .word 0 /* Operating system minor version number */
+ .word 0 /* Image major version number */
+ .word 0 /* Image minor version number */
+ .word 0 /* Subsystem major version number */
+ .word 0 /* Subsystem minor version number */
+ .long 0 /* Reserved */
+ .long _filesz /* Total image size */
+ .long _prefix_filesz /* Total header size */
+ .long 0 /* "Checksum" */
+ .word 0x0a /* Subsystem: EFI */
+ .word 0 /* DLL characteristics */
+ .long 0 /* Size of stack reserve */
+ .long 0 /* Size of stack commit */
+ .long 0 /* Size of heap reserve */
+ .long 0 /* Size of heap commit */
+ .long 0 /* Loader flags */
+ .long 16 /* Number of data directory entries */
+ .long 0, 0 /* Export directory */
+ .long 0, 0 /* Import directory */
+ .long 0, 0 /* Resource directory */
+ .long 0, 0 /* Exception directory */
+ .long 0, 0 /* Security directory */
+ .long _reloc_lma, _reloc_filesz /* Base relocation directory */
+ .long debugdir_lma, debugdir_size /* Debug directory */
+ .long 0, 0 /* Description directory */
+ .long 0, 0 /* Special directory */
+ .long 0, 0 /* Thread storage directory */
+ .long 0, 0 /* Load configuration directory */
+ .long 0, 0 /* Bound import directory */
+ .long 0, 0 /* Import address table directory */
+ .long 0, 0 /* Delay import directory */
+ .long 0, 0 /* Reserved */
+ .long 0, 0 /* Reserved */
+ .size opthdr, . - opthdr
+ .equ opthdr_size, . - opthdr
+
+ /* PE sections */
+pe_sections:
+text_section:
+ .asciz ".text" /* Section name */
+ .align 8
+ .long _text_filesz /* Section size */
+ .long _text_lma /* Relative Virtual Address */
+ .long _text_filesz /* Section size (rounded up) */
+ .long _text_lma /* Pointer to raw data */
+ .long 0 /* Link-time relocations */
+ .long 0 /* Line numbers */
+ .word 0 /* Number of link-time relocations */
+ .word 0 /* Number of line numbers */
+ .long 0x68000020 /* Characteristics */
+rodata_section:
+ .asciz ".rodata" /* Section name */
+ .align 8
+ .long _rodata_filesz /* Section size */
+ .long _rodata_lma /* Relative Virtual Address */
+ .long _rodata_filesz /* Section size (rounded up) */
+ .long _rodata_lma /* Pointer to raw data */
+ .long 0 /* Link-time relocations */
+ .long 0 /* Line numbers */
+ .word 0 /* Number of link-time relocations */
+ .word 0 /* Number of line numbers */
+ .long 0x48000040 /* Characteristics */
+data_section:
+ .asciz ".data" /* Section name */
+ .align 8
+ .long _data_filesz /* Section size */
+ .long _data_lma /* Relative Virtual Address */
+ .long _data_filesz /* Section size (rounded up) */
+ .long _data_lma /* Pointer to raw data */
+ .long 0 /* Link-time relocations */
+ .long 0 /* Line numbers */
+ .word 0 /* Number of link-time relocations */
+ .word 0 /* Number of line numbers */
+ .long 0xc8000040 /* Characteristics */
+reloc_section:
+ .asciz ".reloc" /* Section name */
+ .align 8
+ .long _reloc_filesz /* Section size */
+ .long _reloc_lma /* Relative Virtual Address */
+ .long _reloc_filesz /* Section size (rounded up) */
+ .long _reloc_lma /* Pointer to raw data */
+ .long 0 /* Link-time relocations */
+ .long 0 /* Line numbers */
+ .word 0 /* Number of link-time relocations */
+ .word 0 /* Number of line numbers */
+ .long 0x42000040 /* Characteristics */
+
+pe_sections_end:
+ .size pe_sections, . - pe_sections
+ .equ num_pe_sections, ( ( . - pe_sections ) / 0x28 )
+
+ /* Debug directory */
+ .section ".rodata"
+ .globl debugdir
+debugdir:
+ .long 0 /* Characteristics */
+ .long 0x10d1a884 /* Timestamp */
+ .word 0 /* Major version */
+ .word 0 /* Minor version */
+ .long 0x02 /* RSDS? */
+ .long codeview_rsds_size /* Size of data */
+ .long codeview_rsds_lma /* RVA */
+ .long codeview_rsds_lma /* File offset */
+ .size debugdir, . - debugdir
+ .equ debugdir_size, . - debugdir
+ /* Codeview structure */
+ .globl codeview_rsds
+codeview_rsds:
+ .ascii "RSDS" /* Magic number */
+ .long 0, 0, 0, 0, 0 /* Unused by EFI */
+ .asciz "efiprefix.pdb"
+ .size codeview_rsds, . - codeview_rsds
+ .equ codeview_rsds_size, . - codeview_rsds
diff --git a/gpxe/src/arch/i386/prefix/hdprefix.S b/gpxe/src/arch/i386/prefix/hdprefix.S
index 56fcb36d..086d7f45 100644
--- a/gpxe/src/arch/i386/prefix/hdprefix.S
+++ b/gpxe/src/arch/i386/prefix/hdprefix.S
@@ -63,9 +63,9 @@ max_sector:
max_head:
.byte 0
load_length:
- .long _load_size_sect
+ .long _filesz_sect
- .section ".zinfo.fixup", "a" /* Compressor fixup information */
+ .section ".zinfo.fixup", "a", @progbits /* Compressor fixups */
.ascii "SUBL"
.long load_length
.long 512
@@ -82,6 +82,7 @@ load_failed:
.byte 0x55, 0xaa
start_image:
+ /* Install gPXE */
call install
/* Set up real-mode stack */
@@ -97,7 +98,10 @@ start_image:
pushl $main
pushw %cs
call prot_call
- popl %eax /* discard */
+ popl %ecx /* discard */
+
+ /* Uninstall gPXE */
+ call uninstall
/* Boot next device */
int $0x18
diff --git a/gpxe/src/arch/i386/prefix/kkpxeprefix.S b/gpxe/src/arch/i386/prefix/kkpxeprefix.S
new file mode 100644
index 00000000..38300bed
--- /dev/null
+++ b/gpxe/src/arch/i386/prefix/kkpxeprefix.S
@@ -0,0 +1,8 @@
+/*****************************************************************************
+ * PXE prefix that keep the whole PXE stack present
+ *****************************************************************************
+ */
+
+#define PXELOADER_KEEP_UNDI
+#define PXELOADER_KEEP_PXE
+#include "pxeprefix.S"
diff --git a/gpxe/src/arch/i386/prefix/libprefix.S b/gpxe/src/arch/i386/prefix/libprefix.S
index ae2a491f..56ca64d9 100644
--- a/gpxe/src/arch/i386/prefix/libprefix.S
+++ b/gpxe/src/arch/i386/prefix/libprefix.S
@@ -199,6 +199,39 @@ print_pci_busdevfn:
ret
.size print_pci_busdevfn, . - print_pci_busdevfn
+/*****************************************************************************
+ * Utility function: clear current line
+ *
+ * Parameters:
+ * %ds:di : output buffer (or %di=0 to print to console)
+ * Returns:
+ * %ds:di : next character in output buffer (if applicable)
+ *****************************************************************************
+ */
+ .section ".prefix.lib"
+ .code16
+ .globl print_kill_line
+print_kill_line:
+ /* Preserve registers */
+ pushw %ax
+ pushw %cx
+ /* Print CR */
+ movb $'\r', %al
+ call print_character
+ /* Print 79 spaces */
+ movb $' ', %al
+ movw $79, %cx
+1: call print_character
+ loop 1b
+ /* Print CR */
+ movb $'\r', %al
+ call print_character
+ /* Restore registers and return */
+ popw %cx
+ popw %ax
+ ret
+ .size print_kill_line, . - print_kill_line
+
/****************************************************************************
* pm_call (real-mode near call)
*
@@ -308,7 +341,7 @@ pm_call:
/* Switch CPU to protected mode and load up segment registers */
pushl %eax
cli
- lgdt PM_CALL_VAR(gdt)(%bp)
+ data32 lgdt PM_CALL_VAR(gdt)(%bp)
movl %cr0, %eax
orb $CR0_PE, %al
movl %eax, %cr0
@@ -344,7 +377,7 @@ pm_call:
popw %es
popw %fs
popw %gs
- lgdt PM_CALL_VAR(pm_saved_gdt)(%bp)
+ data32 lgdt PM_CALL_VAR(pm_saved_gdt)(%bp)
popfl
movw %bp, %sp
popw %bp
@@ -504,31 +537,89 @@ install_block:
.code16
.globl alloc_basemem
alloc_basemem:
+ /* Preserve registers */
+ pushw %fs
+
/* FBMS => %ax as segment address */
- movw $0x40, %ax
- movw %ax, %fs
+ pushw $0x40
+ popw %fs
movw %fs:0x13, %ax
shlw $6, %ax
- /* .data16 segment address */
- subw $_data16_size_pgh, %ax
+ /* Calculate .data16 segment address */
+ subw $_data16_memsz_pgh, %ax
pushw %ax
- /* .text16 segment address */
- subw $_text16_size_pgh, %ax
+ /* Calculate .text16 segment address */
+ subw $_text16_memsz_pgh, %ax
pushw %ax
/* Update FBMS */
shrw $6, %ax
movw %ax, %fs:0x13
- /* Return */
+ /* Retrieve .text16 and .data16 segment addresses */
popw %ax
popw %bx
+
+ /* Restore registers and return */
+ popw %fs
ret
.size alloc_basemem, . - alloc_basemem
/****************************************************************************
+ * free_basemem (real-mode near call)
+ *
+ * Free space allocated with alloc_basemem.
+ *
+ * Parameters:
+ * %ax : .text16 segment address
+ * %bx : .data16 segment address
+ * Returns:
+ * %ax : 0 if successfully freed
+ * Corrupts:
+ * none
+ ****************************************************************************
+ */
+ .section ".text16"
+ .code16
+ .globl free_basemem
+free_basemem:
+ /* Preserve registers */
+ pushw %fs
+
+ /* Check FBMS counter */
+ pushw %ax
+ shrw $6, %ax
+ pushw $0x40
+ popw %fs
+ cmpw %ax, %fs:0x13
+ popw %ax
+ jne 1f
+
+ /* Check hooked interrupt count */
+ cmpw $0, %cs:hooked_bios_interrupts
+ jne 1f
+
+ /* OK to free memory */
+ addw $_text16_memsz_pgh, %ax
+ addw $_data16_memsz_pgh, %ax
+ shrw $6, %ax
+ movw %ax, %fs:0x13
+ xorw %ax, %ax
+
+1: /* Restore registers and return */
+ popw %fs
+ ret
+ .size free_basemem, . - free_basemem
+
+ .section ".text16.data"
+ .globl hooked_bios_interrupts
+hooked_bios_interrupts:
+ .word 0
+ .size hooked_bios_interrupts, . - hooked_bios_interrupts
+
+/****************************************************************************
* install (real-mode near call)
*
* Install all text and data segments.
@@ -594,19 +685,19 @@ install_prealloc:
jnz 1f
movw %cs, %si
shll $4, %esi
-1: addl $_payload_offset, %esi
+1: addl $_payload_lma, %esi
/* Install .text16 and .data16 */
pushl %edi
movzwl %ax, %edi
shll $4, %edi
- movl $_text16_size, %ecx
+ movl $_text16_memsz, %ecx
movl %ecx, %edx
call install_block /* .text16 */
movzwl %bx, %edi
shll $4, %edi
- movl $_data16_progbits_size, %ecx
- movl $_data16_size, %edx
+ movl $_data16_filesz, %ecx
+ movl $_data16_memsz, %edx
call install_block /* .data16 */
popl %edi
@@ -622,8 +713,8 @@ install_prealloc:
* prior to reading the E820 memory map and relocating
* properly.
*/
- movl $_textdata_progbits_size, %ecx
- movl $_textdata_size, %edx
+ movl $_textdata_filesz, %ecx
+ movl $_textdata_memsz, %edx
call install_block
/* Initialise librm at current location */
@@ -676,30 +767,53 @@ prot_call_vector:
.size prot_call_vector, . - prot_call_vector
#endif
+/****************************************************************************
+ * uninstall (real-mode near call)
+ *
+ * Uninstall all text and data segments.
+ *
+ * Parameters:
+ * %ax : .text16 segment address
+ * %bx : .data16 segment address
+ * Returns:
+ * none
+ * Corrupts:
+ * none
+ ****************************************************************************
+ */
+ .section ".text16"
+ .code16
+ .globl uninstall
+uninstall:
+ call free_basemem
+ ret
+ .size uninstall, . - uninstall
+
+
/* File split information for the compressor */
#if COMPRESS
- .section ".zinfo", "a"
+ .section ".zinfo", "a", @progbits
.ascii "COPY"
- .long _prefix_load_offset
- .long _prefix_progbits_size
+ .long _prefix_lma
+ .long _prefix_filesz
.long _max_align
.ascii "PACK"
- .long _text16_load_offset
- .long _text16_progbits_size
+ .long _text16_lma
+ .long _text16_filesz
.long _max_align
.ascii "PACK"
- .long _data16_load_offset
- .long _data16_progbits_size
+ .long _data16_lma
+ .long _data16_filesz
.long _max_align
.ascii "PACK"
- .long _textdata_load_offset
- .long _textdata_progbits_size
+ .long _textdata_lma
+ .long _textdata_filesz
.long _max_align
#else /* COMPRESS */
- .section ".zinfo", "a"
+ .section ".zinfo", "a", @progbits
.ascii "COPY"
- .long _prefix_load_offset
- .long _load_size
+ .long _prefix_lma
+ .long _filesz
.long _max_align
#endif /* COMPRESS */
diff --git a/gpxe/src/arch/i386/prefix/lkrnprefix.S b/gpxe/src/arch/i386/prefix/lkrnprefix.S
index c1e92f57..094263d2 100644
--- a/gpxe/src/arch/i386/prefix/lkrnprefix.S
+++ b/gpxe/src/arch/i386/prefix/lkrnprefix.S
@@ -92,9 +92,9 @@ setup_sects:
root_flags:
.word 0
syssize:
- .long _load_size_pgh - PREFIXPGH
+ .long _filesz_pgh - PREFIXPGH
- .section ".zinfo.fixup", "a" /* Compressor fixup information */
+ .section ".zinfo.fixup", "a", @progbits /* Compressor fixups */
.ascii "SUBL"
.long syssize
.long 16
@@ -189,6 +189,7 @@ run_gpxe:
movw %ax, %ss
movw $0x7c00, %sp
+ /* Install gPXE */
call install
/* Set up real-mode stack */
@@ -204,7 +205,10 @@ run_gpxe:
pushl $main
pushw %cs
call prot_call
- popl %eax /* discard */
+ popl %ecx /* discard */
+
+ /* Uninstall gPXE */
+ call uninstall
/* Boot next device */
int $0x18
diff --git a/gpxe/src/arch/i386/prefix/nbiprefix.S b/gpxe/src/arch/i386/prefix/nbiprefix.S
index d4904b73..d1753e30 100644
--- a/gpxe/src/arch/i386/prefix/nbiprefix.S
+++ b/gpxe/src/arch/i386/prefix/nbiprefix.S
@@ -32,11 +32,11 @@ segment_header:
.byte 0
.byte 0x04 /* Last segment */
.long 0x00007e00
-imglen: .long _load_size - 512
-memlen: .long _load_size - 512
+imglen: .long _filesz - 512
+memlen: .long _filesz - 512
.size segment_header, . - segment_header
- .section ".zinfo.fixup", "a" /* Compressor fixup information */
+ .section ".zinfo.fixup", "a", @progbits /* Compressor fixups */
.ascii "SUBL"
.long imglen
.long 1
@@ -52,7 +52,7 @@ memlen: .long _load_size - 512
*****************************************************************************
*/
entry:
- /* Install low and high memory regions */
+ /* Install gPXE */
call install
/* Jump to .text16 segment */
@@ -64,7 +64,10 @@ entry:
pushl $main
pushw %cs
call prot_call
- popl %eax /* discard */
+ popl %ecx /* discard */
+
+ /* Uninstall gPXE */
+ call uninstall
/* Reboot system */
int $0x19
diff --git a/gpxe/src/arch/i386/prefix/pxeprefix.S b/gpxe/src/arch/i386/prefix/pxeprefix.S
index 302f8e5d..a5f0c711 100644
--- a/gpxe/src/arch/i386/prefix/pxeprefix.S
+++ b/gpxe/src/arch/i386/prefix/pxeprefix.S
@@ -2,7 +2,7 @@
#define PXENV_UNDI_GET_NIC_TYPE 0x0012
#define PXENV_STOP_UNDI 0x0015
#define PXENV_UNLOAD_STACK 0x0070
-
+
.text
.arch i386
.org 0
@@ -12,36 +12,39 @@
#include <undi.h>
+#define STACK_MAGIC ( 'L' + ( 'R' << 8 ) + ( 'E' << 16 ) + ( 'T' << 24 ) )
+
/*****************************************************************************
* Entry point: set operating context, print welcome message
*****************************************************************************
*/
.section ".prefix"
- /* Set up our non-stack segment registers */
jmp $0x7c0, $1f
-1: pushfl
- /* %ax here is the default return type... */
- movw $5, %ax /* Keep PXE+UNDI */
+1:
+ /* Preserve registers for possible return to PXE */
+ pushfl
pushal
- pushw %ds
- pushw %es
- pushw %fs
pushw %gs
+ pushw %fs
+ pushw %es
+ pushw %ds
+
+ /* Store magic word on PXE stack and remember PXE %ss:esp */
+ pushl $STACK_MAGIC
+ movw %ss, %cs:pxe_ss
+ movl %esp, %cs:pxe_esp
+
+ /* Set up our non-stack segment registers */
movw %cs, %ax
movw %ax, %ds
-
movw $0x40, %ax /* BIOS data segment access */
movw %ax, %fs
-
- pushw %fs:0x13
/* Record PXENV+ and !PXE nominal addresses */
- movw %es, pxenv_segment
+ movw %es, %ax /* PXENV+ address */
+ movw %ax, pxenv_segment
movw %bx, pxenv_offset
- movw %sp, %bp
- movw %ss, return_stack_segment
- movl %esp, return_stack_offset
- movl 50(%bp), %eax
- movl %eax, ppxe_segoff /* !PXE address */
+ popl %eax /* Discard return address */
+ popl ppxe_segoff /* !PXE address */
/* Set up stack just below 0x7c00 */
xorw %ax, %ax
movw %ax, %ss
@@ -60,7 +63,7 @@
* Verify PXENV+ structure and record parameters of interest
*****************************************************************************
*/
-detect_pxenv:
+ect_pxenv:
/* Signature check */
les pxenv_segoff, %bx
cmpl $0x4e455850, %es:(%bx) /* 'PXEN' signature */
@@ -264,7 +267,7 @@ no_physical_device:
* Leave NIC in a safe state
*****************************************************************************
*/
-#ifndef PXELOADER_KEEP_UNDI
+#ifndef PXELOADER_KEEP_PXE
shutdown_nic:
/* Issue PXENV_UNDI_SHUTDOWN */
movw $PXENV_UNDI_SHUTDOWN, %bx
@@ -272,11 +275,6 @@ shutdown_nic:
jnc 1f
call print_pxe_error
1:
-
-/*****************************************************************************
- * Unload PXE base code
- *****************************************************************************
- */
unload_base_code:
/* Issue PXENV_UNLOAD_STACK */
movw $PXENV_UNLOAD_STACK, %bx
@@ -289,12 +287,14 @@ unload_base_code:
movw %fs:(0x13), %bx
call free_basemem
99:
+ andw $~( UNDI_FL_INITIALIZED | UNDI_FL_KEEP_ALL ), flags
+#endif /* PXELOADER_KEEP_PXE */
/*****************************************************************************
* Unload UNDI driver
*****************************************************************************
*/
-
+#ifndef PXELOADER_KEEP_UNDI
unload_undi:
/* Issue PXENV_STOP_UNDI */
movw $PXENV_STOP_UNDI, %bx
@@ -309,6 +309,7 @@ unload_undi:
/* Clear UNDI_FL_STARTED */
andw $~UNDI_FL_STARTED, flags
99:
+#endif /* PXELOADER_KEEP_UNDI */
/*****************************************************************************
* Print remaining free base memory
@@ -325,15 +326,14 @@ print_free_basemem:
10: .asciz " "
20: .asciz "kB free base memory after PXE unload\n"
.previous
-#endif /* PXELOADER_KEEP_UNDI */
/*****************************************************************************
* Exit point
*****************************************************************************
*/
finished:
- jmp run_etherboot
-
+ jmp run_gpxe
+
/*****************************************************************************
* Subroutine: print segment:offset address
*
@@ -527,6 +527,10 @@ print_pxe_error:
* PXE data structures
*****************************************************************************
*/
+ .section ".prefix.data"
+
+pxe_ss: .word 0
+pxe_esp: .long 0
pxe_parameter_structure: .fill 20
@@ -554,12 +558,6 @@ entry_segoff:
entry_offset: .word 0
entry_segment: .word 0
-return_stack_segoff:
-return_stack_offset: .long 0
-return_stack_segment: .word 0
-
-return_type: .word 0 /* Default: unload PXE and boot next */
-
undi_fbms_start: .word 0
undi_fbms_end: .word 0
@@ -569,16 +567,18 @@ isapnp_read_port: .word UNDI_NO_ISAPNP_READ_PORT
pci_vendor: .word 0
pci_device: .word 0
-flags: .word UNDI_FL_STARTED
+flags:
+ .word ( UNDI_FL_INITIALIZED | UNDI_FL_STARTED | UNDI_FL_KEEP_ALL )
.equ undi_device_size, ( . - undi_device )
/*****************************************************************************
- * Run Etherboot main code
+ * Run gPXE main code
*****************************************************************************
- */
-run_etherboot:
- /* Install Etherboot */
+ */
+ .section ".prefix"
+run_gpxe:
+ /* Install gPXE */
call install
/* Set up real-mode stack */
@@ -594,6 +594,10 @@ run_etherboot:
rep movsb
#endif
+ /* Retrieve PXE %ss:esp */
+ movw pxe_ss, %di
+ movl pxe_esp, %ebp
+
/* Jump to .text16 segment with %ds pointing to .data16 */
movw %bx, %ds
pushw %ax
@@ -605,29 +609,30 @@ run_etherboot:
pushl $main
pushw %cs
call prot_call
- popl %eax /* discard */
+ popl %ecx /* discard */
-#ifdef PXELOADER_KEEP_UNDI
- /* Boot next device */
- movw $0x40, %ax
- movw %ax, %fs
- movw $preloaded_undi,%bx
-
- cli
- movw %ss:return_type-undi_device(%bx),%ax
- lssl %ss:return_stack_segoff-undi_device(%bx), %esp
- movw %sp,%bp
- movw %ax,38(%bp) /* Overwrite return AX value */
- popw %fs:0x13 /* 0 */
- popw %gs /* 2 */
- popw %fs /* 4 */
- popw %es /* 6 */
- popw %ds /* 8 */
- popal /* 10, 14, 18, 22, 26, 30, 34, 38 */
- popfl /* 42 */
- lret /* 46 */
-#else
- int $0x18
-#endif
+ /* Uninstall gPXE */
+ call uninstall
+
+ /* Restore PXE stack */
+ movw %di, %ss
+ movl %ebp, %esp
+ /* Check PXE stack magic */
+ popl %eax
+ cmpl $STACK_MAGIC, %eax
+ jne 1f
+
+ /* PXE stack OK: return to caller */
+ popw %ds
+ popw %es
+ popw %fs
+ popw %gs
+ popal
+ popfl
+ xorw %ax, %ax /* Return success */
+ lret
+
+1: /* PXE stack corrupt or removed: use INT 18 */
+ int $0x18
.previous
diff --git a/gpxe/src/arch/i386/prefix/romprefix.S b/gpxe/src/arch/i386/prefix/romprefix.S
index 92a931cd..a6431cd9 100644
--- a/gpxe/src/arch/i386/prefix/romprefix.S
+++ b/gpxe/src/arch/i386/prefix/romprefix.S
@@ -14,6 +14,7 @@
#define STACK_MAGIC ( 'L' + ( 'R' << 8 ) + ( 'E' << 16 ) + ( 'T' << 24 ) )
#define PNP_GET_BBS_VERSION 0x60
#define PMM_ALLOCATE 0x0000
+#define PMM_DEALLOCATE 0x0002
/* ROM banner timeout. Based on the configurable BANNER_TIMEOUT in
* config.h, but converted to a number of (18Hz) timer ticks, and
@@ -30,7 +31,7 @@
.org 0x00
romheader:
.word 0xAA55 /* BIOS extension signature */
-romheader_size: .byte _load_size_sect /* Size in 512-byte blocks */
+romheader_size: .byte _filesz_sect /* Size in 512-byte blocks */
jmp init /* Initialisation vector */
checksum:
.byte 0
@@ -42,7 +43,7 @@ checksum:
.word pnpheader
.size romheader, . - romheader
- .section ".zinfo.fixup", "a" /* Compressor fixup information */
+ .section ".zinfo.fixup", "a", @progbits /* Compressor fixups */
.ascii "SUBB"
.long romheader_size
.long 512
@@ -58,18 +59,18 @@ pciheader:
.byte 0x03 /* PCI data structure revision */
.byte 0x02, 0x00, 0x00 /* Class code */
pciheader_image_length:
- .word _load_size_sect /* Image length */
+ .word _filesz_sect /* Image length */
.word 0x0001 /* Revision level */
.byte 0x00 /* Code type */
.byte 0x80 /* Last image indicator */
pciheader_runtime_length:
- .word _load_size_sect /* Maximum run-time image length */
+ .word _filesz_sect /* Maximum run-time image length */
.word 0x0000 /* Configuration utility code header */
.word 0x0000 /* DMTF CLP entry point */
.equ pciheader_len, . - pciheader
.size pciheader, . - pciheader
- .section ".zinfo.fixup", "a" /* Compressor fixup information */
+ .section ".zinfo.fixup", "a", @progbits /* Compressor fixups */
.ascii "SUBW"
.long pciheader_image_length
.long 512
@@ -109,12 +110,12 @@ mfgstr:
/* Product string
*
- * Defaults to "gPXE". If the ROM image is writable at initialisation
- * time, it will be filled in to include the PCI bus:dev.fn number of
- * the card as well.
+ * Defaults to PRODUCT_SHORT_NAME. If the ROM image is writable at
+ * initialisation time, it will be filled in to include the PCI
+ * bus:dev.fn number of the card as well.
*/
prodstr:
- .ascii "gPXE"
+ .ascii PRODUCT_SHORT_NAME
prodstr_separator:
.byte 0
.ascii "(PCI "
@@ -130,9 +131,9 @@ undiheader:
.byte 0 /* Structure revision */
.byte 0,1,2 /* PXE version: 2.1.0 */
.word undiloader /* Offset to loader routine */
- .word _data16_size /* Stack segment size */
- .word _data16_size /* Data segment size */
- .word _text16_size /* Code segment size */
+ .word _data16_memsz /* Stack segment size */
+ .word _data16_memsz /* Data segment size */
+ .word _text16_memsz /* Code segment size */
.ascii "PCIR" /* Bus type */
.equ undiheader_len, . - undiheader
.size undiheader, . - undiheader
@@ -190,11 +191,11 @@ init:
stc
movw $0xb101, %ax
int $0x1a
- jc 1f
+ jc no_pci3
cmpl $PCI_SIGNATURE, %edx
- jne 1f
+ jne no_pci3
testb %ah, %ah
- jnz 1f
+ jnz no_pci3
movw $init_message_pci, %si
xorw %di, %di
call print_message
@@ -205,11 +206,33 @@ init:
movb %bl, %al
call print_hex_byte
cmpb $3, %bh
- jae 2f
-1: /* PCI <3.0: set %gs (runtime segment) = %cs (init-time segment) */
+ jb no_pci3
+ /* PCI >=3.0: leave %gs as-is if sane */
+ movw %gs, %ax
+ cmpw $0xa000, %ax /* Insane if %gs < 0xa000 */
+ jb pci3_insane
+ movw %cs, %bx /* Sane if %cs == %gs */
+ cmpw %bx, %ax
+ je 1f
+ movzbw romheader_size, %cx /* Sane if %cs+len <= %gs */
+ shlw $5, %cx
+ addw %cx, %bx
+ cmpw %bx, %ax
+ jae 1f
+ movw %cs, %bx /* Sane if %gs+len <= %cs */
+ addw %cx, %ax
+ cmpw %bx, %ax
+ jbe 1f
+pci3_insane: /* PCI 3.0 with insane %gs value: print error and ignore %gs */
+ movb $'!', %al
+ call print_character
+ movw %gs, %ax
+ call print_hex_word
+no_pci3:
+ /* PCI <3.0: set %gs (runtime segment) = %cs (init-time segment) */
pushw %cs
popw %gs
-2: popl %edi
+1: popl %edi
popl %edx
popl %ebx
@@ -268,21 +291,52 @@ pmm_scan:
movw $init_message_pmm, %si
xorw %di, %di
call print_message
- /* Try to allocate 2MB block via PMM */
+ /* We have PMM and so a 1kB stack: preserve upper register halves */
+ pushal
+ /* Calculate required allocation size in %esi */
+ movzbl romheader_size, %eax
+ shll $9, %eax
+ addl $_textdata_memsz, %eax
+ orw $0xffff, %ax /* Ensure allocation size is at least 64kB */
+ bsrl %eax, %ecx
+ subw $15, %cx /* Round up and convert to 64kB count */
+ movw $1, %si
+ shlw %cl, %si
+pmm_loop:
+ /* Try to allocate block via PMM */
pushw $0x0006 /* Aligned, extended memory */
pushl $0xffffffff /* No handle */
- pushl $( 0x00200000 / 16 ) /* 2MB in paragraphs */
+ movzwl %si, %eax
+ shll $12, %eax
+ pushl %eax /* Allocation size in paragraphs */
pushw $PMM_ALLOCATE
lcall *%es:7
addw $12, %sp
+ /* Abort if allocation fails */
+ testw %dx, %dx /* %ax==0 even on success, since align>=64kB */
+ jz pmm_fail
+ /* If block has A20==1, free block and try again with twice
+ * the allocation size (and hence alignment).
+ */
+ testw $0x0010, %dx
+ jz got_pmm
+ pushw %dx
+ pushw $0
+ pushw $PMM_DEALLOCATE
+ lcall *%es:7
+ addw $6, %sp
+ addw %si, %si
+ jmp pmm_loop
+got_pmm: /* PMM allocation succeeded */
+ movw %dx, ( image_source + 2 )
movw %dx, %ax
xorw %di, %di
call print_hex_word
- movw %dx, ( image_source + 2 )
- testw %dx, %dx /* %ax==0 even on success, since align=2MB */
- jz no_pmm
- /* PMM allocation succeeded: copy ROM to PMM block */
- pushal /* PMM presence implies 1kB stack */
+ movb $'@', %al
+ call print_character
+ movw %si, %ax
+ call print_hex_byte
+ /* Copy ROM to PMM block */
xorw %ax, %ax
movw %ax, %es
movl image_source, %edi
@@ -294,13 +348,15 @@ pmm_scan:
/* Shrink ROM and update checksum */
xorw %bx, %bx
xorw %si, %si
- movw $_prefix_size_sect, %cx
+ movw $_prefix_memsz_sect, %cx
movb %cl, romheader_size
shlw $9, %cx
1: lodsb
addb %al, %bl
loop 1b
subb %bl, checksum
+pmm_fail:
+ /* Restore upper register halves */
popal
no_pmm:
@@ -324,23 +380,28 @@ no_pmm:
movw $init_message_prompt, %si
xorw %di, %di
call print_message
+ movw $prodstr, %si
+ call print_message
+ movw $init_message_dots, %si
+ call print_message
/* Wait for Ctrl-B */
movw $0xff02, %bx
call wait_for_key
/* Clear prompt */
pushf
- movw $clear_message, %si
xorw %di, %di
+ call print_kill_line
+ movw $init_message_done, %si
call print_message
popf
- jnz 1f
+ jnz 2f
/* Ctrl-B was pressed: invoke gPXE. The keypress will be
* picked up by the initial shell prompt, and we will drop
* into a shell.
*/
pushw %cs
call exec
-1:
+2:
/* Restore registers */
popw %gs
popw %fs
@@ -353,7 +414,26 @@ no_pmm:
lret
.size init, . - init
+/*
+ * Note to hardware vendors:
+ *
+ * If you wish to brand this boot ROM, please do so by defining the
+ * strings PRODUCT_NAME and PRODUCT_SHORT_NAME in config/general.h.
+ *
+ * While nothing in the GPL prevents you from removing all references
+ * to gPXE or http://etherboot.org, we prefer you not to do so.
+ *
+ * If you have an OEM-mandated branding requirement that cannot be
+ * satisfied simply by defining PRODUCT_NAME and PRODUCT_SHORT_NAME,
+ * please contact us.
+ *
+ * [ Including an ASCII NUL in PRODUCT_NAME is considered to be
+ * bypassing the spirit of this request! ]
+ */
init_message:
+ .ascii "\n"
+ .ascii PRODUCT_NAME
+ .ascii "\n"
.asciz "gPXE (http://etherboot.org) - "
.size init_message, . - init_message
init_message_pci:
@@ -372,11 +452,14 @@ init_message_int19:
.asciz " INT19"
.size init_message_int19, . - init_message_int19
init_message_prompt:
- .asciz "\nPress Ctrl-B to configure gPXE..."
+ .asciz "\nPress Ctrl-B to configure "
.size init_message_prompt, . - init_message_prompt
-clear_message:
- .asciz "\r \n\n"
- .size clear_message, . - clear_message
+init_message_dots:
+ .asciz "..."
+ .size init_message_dots, . - init_message_dots
+init_message_done:
+ .asciz "\n\n"
+ .size init_message_done, . - init_message_done
/* ROM image location
*
@@ -432,8 +515,9 @@ int19_entry:
movw $0xdf42, %bx
call wait_for_key
pushf
- movw $clear_message, %si
xorw %di, %di
+ call print_kill_line
+ movw $int19_message_done, %si
call print_message
popf
jnz 1f
@@ -460,6 +544,9 @@ int19_message_prompt:
int19_message_dots:
.asciz "..."
.size int19_message_dots, . - int19_message_dots
+int19_message_done:
+ .asciz "\n\n"
+ .size int19_message_done, . - int19_message_done
/* Execute as a boot device
*
@@ -504,8 +591,11 @@ exec: /* Set %ds = %cs */
pushl $main
pushw %cs
call prot_call
- /* No need to clean up stack; we are about to reload %ss:sp */
-
+ popl %ecx /* discard */
+
+ /* Uninstall gPXE */
+ call uninstall
+
/* Restore BIOS stack */
movw %dx, %ss
movw %bp, %sp
diff --git a/gpxe/src/arch/i386/scripts/efi.lds b/gpxe/src/arch/i386/scripts/efi.lds
new file mode 100644
index 00000000..b6255a68
--- /dev/null
+++ b/gpxe/src/arch/i386/scripts/efi.lds
@@ -0,0 +1,180 @@
+/* -*- sh -*- */
+
+/*
+ * Linker script for EFI images
+ *
+ */
+
+EXTERN ( efi_entry )
+
+SECTIONS {
+
+ /* The file starts at a virtual address of zero, and sections are
+ * contiguous. Each section is aligned to at least _max_align,
+ * which defaults to 32. Load addresses are equal to virtual
+ * addresses.
+ */
+
+ . = 0;
+ PROVIDE ( _max_align = 32 );
+
+ /*
+ * The prefix
+ *
+ */
+
+ .prefix : {
+ _prefix = .;
+ *(.prefix)
+ *(.prefix.*)
+ _mprefix = .;
+ } .bss.prefix (NOLOAD) : {
+ _eprefix = .;
+ }
+ _prefix_filesz = ABSOLUTE ( _mprefix - _prefix );
+ _prefix_memsz = ABSOLUTE ( _eprefix - _prefix );
+
+ /*
+ * The text section
+ *
+ */
+
+ . = ALIGN ( _max_align );
+ .text : {
+ _text = .;
+ *(.text)
+ *(.text.*)
+ _mtext = .;
+ } .bss.text (NOLOAD) : {
+ _etext = .;
+ }
+ _text_filesz = ABSOLUTE ( _mtext - _text );
+ _text_memsz = ABSOLUTE ( _etext - _text );
+
+ /*
+ * The rodata section
+ *
+ */
+
+ . = ALIGN ( _max_align );
+ .rodata : {
+ _rodata = .;
+ *(.rodata)
+ *(.rodata.*)
+ _mrodata = .;
+ } .bss.rodata (NOLOAD) : {
+ _erodata = .;
+ }
+ _rodata_filesz = ABSOLUTE ( _mrodata - _rodata );
+ _rodata_memsz = ABSOLUTE ( _erodata - _rodata );
+
+ /*
+ * The data section
+ *
+ */
+
+ . = ALIGN ( _max_align );
+ .data : {
+ _data = .;
+ *(.data)
+ *(.data.*)
+ *(SORT(.tbl.*)) /* Various tables. See include/tables.h */
+ /* EFI seems to not support proper bss sections */
+ *(.bss)
+ *(.bss.*)
+ *(COMMON)
+ *(.stack)
+ *(.stack.*)
+ _mdata = .;
+ } .bss.data (NOLOAD) : {
+ _edata = .;
+ }
+ _data_filesz = ABSOLUTE ( _mdata - _data );
+ _data_memsz = ABSOLUTE ( _edata - _data );
+
+ /*
+ * The bss section
+ *
+ */
+
+ . = ALIGN ( _max_align );
+ .bss : {
+ _bss = .;
+ /* EFI seems to not support proper bss sections */
+ _mbss = .;
+ } .bss.bss (NOLOAD) : {
+ _ebss = .;
+ }
+ _bss_filesz = ABSOLUTE ( _mbss - _bss );
+ _bss_memsz = ABSOLUTE ( _ebss - _bss );
+
+ /*
+ * The reloc section
+ *
+ */
+
+ . = ALIGN ( _max_align );
+ .reloc : {
+ _reloc = .;
+ /* Provide some dummy contents to force ld to include this
+ * section. It will be created by the efilink utility.
+ */
+ . += 1;
+ _mreloc = .;
+ } .bss.reloc (NOLOAD) : {
+ _ereloc = .;
+ }
+ _reloc_filesz = ABSOLUTE ( _mreloc - _reloc );
+ _reloc_memsz = ABSOLUTE ( _ereloc - _reloc );
+
+ _filesz = ABSOLUTE ( . );
+
+ /*
+ * Weak symbols that need zero values if not otherwise defined
+ *
+ */
+
+ .weak 0x0 : {
+ _weak = .;
+ *(.weak)
+ _eweak = .;
+ }
+ _assert = ASSERT ( ( _weak == _eweak ), ".weak is non-zero length" );
+
+ /*
+ * Dispose of the comment and note sections to make the link map
+ * easier to read
+ *
+ */
+
+ /DISCARD/ : {
+ *(.comment)
+ *(.comment.*)
+ *(.note)
+ *(.note.*)
+ *(.eh_frame)
+ *(.eh_frame.*)
+ *(.rel)
+ *(.rel.*)
+ }
+
+ /*
+ * Load address calculations.
+ *
+ */
+
+ _prefix_lma = ABSOLUTE ( _prefix );
+ _text_lma = ABSOLUTE ( _text );
+ _rodata_lma = ABSOLUTE ( _rodata );
+ _data_lma = ABSOLUTE ( _data );
+ _bss_lma = ABSOLUTE ( _bss );
+ _reloc_lma = ABSOLUTE ( _reloc );
+
+ /*
+ * Load addresses required by the prefix
+ *
+ */
+ efi_entry_lma = ABSOLUTE ( efi_entry );
+ debugdir_lma = ABSOLUTE ( debugdir );
+ codeview_rsds_lma = ABSOLUTE ( codeview_rsds );
+}
diff --git a/gpxe/src/arch/i386/scripts/i386.lds b/gpxe/src/arch/i386/scripts/i386.lds
index 729ad30a..8a0c6733 100644
--- a/gpxe/src/arch/i386/scripts/i386.lds
+++ b/gpxe/src/arch/i386/scripts/i386.lds
@@ -5,15 +5,9 @@
*
*/
-OUTPUT_FORMAT ( "elf32-i386", "elf32-i386", "elf32-i386" )
-OUTPUT_ARCH ( i386 )
-ENTRY ( _entry )
-
SECTIONS {
- /* All sections in the resulting file have consecutive load
- * addresses, but may have individual link addresses depending on
- * the memory model being used.
+ /* Each section starts at a virtual address of zero.
*
* We guarantee alignment of virtual addresses to any alignment
* specified by the constituent object files (e.g. via
@@ -31,254 +25,185 @@ SECTIONS {
*/
/*
- * Weak symbols that need zero values if not otherwise defined
- */
-
- . = 0;
- .weak : AT ( 0 ) {
- *(.weak)
- }
- _assert = ASSERT ( ( . == 0 ), ".weak is non-zero length" );
-
- /*
* The prefix
+ *
*/
- _prefix_link_addr = 0;
- . = _prefix_link_addr;
- _prefix = .;
-
- .prefix : AT ( _prefix_load_offset + __prefix ) {
- __prefix = .;
- _entry = .;
+ .prefix 0x0 : AT ( _prefix_lma ) {
+ _prefix = .;
*(.prefix)
*(.prefix.*)
- _eprefix_progbits = .;
+ _mprefix = .;
+ } .bss.prefix (NOLOAD) : AT ( _end_lma ) {
+ _eprefix = .;
}
-
- _eprefix = .;
+ _prefix_filesz = ABSOLUTE ( _mprefix - _prefix );
+ _prefix_memsz = ABSOLUTE ( _eprefix - _prefix );
/*
- * The 16-bit sections, if present
+ * The 16-bit (real-mode) code section
+ *
*/
- _text16_link_addr = 0;
- . = _text16_link_addr;
- _text16 = .;
-
- /* We need to allow code at the NULL address in .text16 */
-
- .text16 : AT ( _text16_load_offset + __text16 ) {
- __text16 = .;
+ .text16 0x0 : AT ( _text16_lma ) {
+ _text16 = .;
*(.text16.null)
- . += 1; /* Prevent NULL being valid */
+ . += 1; /* Prevent NULL being valid */
*(.text16)
*(.text16.*)
- _etext16_progbits = .;
- } = 0x9090
-
- _etext16 = .;
-
- _data16_link_addr = 0;
- . = _data16_link_addr;
- _data16 = .;
+ _mtext16 = .;
+ } .bss.text16 (NOLOAD) : AT ( _end_lma ) {
+ _etext16 = .;
+ }
+ _text16_filesz = ABSOLUTE ( _mtext16 - _text16 );
+ _text16_memsz = ABSOLUTE ( _etext16 - _text16 );
- . += 1; /* Prevent NULL being valid */
+ /*
+ * The 16-bit (real-mode) data section
+ *
+ */
- .rodata16 : AT ( _data16_load_offset + __rodata16 ) {
- __rodata16 = .;
+ .data16 0x0 : AT ( _data16_lma ) {
+ _data16 = .;
+ . += 1; /* Prevent NULL being valid */
*(.rodata16)
*(.rodata16.*)
- }
- .data16 : AT ( _data16_load_offset + __data16 ) {
- __data16 = .;
*(.data16)
*(.data16.*)
- _edata16_progbits = .;
- }
- .bss16 : AT ( _data16_load_offset + __bss16 ) {
- __bss16 = .;
- _bss16 = .;
+ _mdata16 = .;
+ } .bss.data16 (NOLOAD) : AT ( _end_lma ) {
*(.bss16)
*(.bss16.*)
- _ebss16 = .;
- }
- .stack16 : AT ( _data16_load_offset + __stack16 ) {
- __stack16 = .;
*(.stack16)
*(.stack16.*)
+ _edata16 = .;
}
-
- _edata16 = .;
+ _data16_filesz = ABSOLUTE ( _mdata16 - _data16 );
+ _data16_memsz = ABSOLUTE ( _edata16 - _data16 );
/*
* The 32-bit sections
+ *
*/
- _textdata_link_addr = 0;
- . = _textdata_link_addr;
- _textdata = .;
-
- _text = .;
-
- . += 1; /* Prevent NULL being valid */
-
- .text : AT ( _textdata_load_offset + __text ) {
- __text = .;
+ .textdata 0x0 : AT ( _textdata_lma ) {
+ _textdata = .;
*(.text.null_trap)
+ . += 1; /* Prevent NULL being valid */
*(.text)
*(.text.*)
- } = 0x9090
-
- _etext = .;
-
- _data = .;
-
- .rodata : AT ( _textdata_load_offset + __rodata ) {
- __rodata = .;
*(.rodata)
*(.rodata.*)
- }
- .data : AT ( _textdata_load_offset + __data ) {
- __data = .;
*(.data)
*(.data.*)
*(SORT(.tbl.*)) /* Various tables. See include/tables.h */
- _etextdata_progbits = .;
- }
- .bss : AT ( _textdata_load_offset + __bss ) {
- __bss = .;
- _bss = .;
+ _mtextdata = .;
+ } .bss.textdata (NOLOAD) : AT ( _end_lma ) {
*(.bss)
*(.bss.*)
*(COMMON)
- _ebss = .;
- }
- .stack : AT ( _textdata_load_offset + __stack ) {
- __stack = .;
*(.stack)
*(.stack.*)
+ _etextdata = .;
}
-
- _edata = .;
-
- _etextdata = .;
-
- _end = .;
+ _textdata_filesz = ABSOLUTE ( _mtextdata - _textdata );
+ _textdata_memsz = ABSOLUTE ( _etextdata - _textdata );
/*
* Compressor information block
+ *
*/
- _zinfo_link_addr = 0;
- . = _zinfo_link_addr;
- _zinfo = .;
-
- .zinfo : AT ( _zinfo_load_offset + __zinfo ) {
- __zinfo = .;
- _entry = .;
+ .zinfo 0x0 : AT ( _zinfo_lma ) {
+ _zinfo = .;
*(.zinfo)
*(.zinfo.*)
- _ezinfo_progbits = .;
+ _mzinfo = .;
+ } .bss.zinfo (NOLOAD) : AT ( _end_lma ) {
+ _ezinfo = .;
}
-
- _ezinfo = .;
+ _zinfo_filesz = ABSOLUTE ( _mzinfo - _zinfo );
+ _zinfo_memsz = ABSOLUTE ( _ezinfo - _zinfo );
+
+ /*
+ * Weak symbols that need zero values if not otherwise defined
+ *
+ */
+
+ .weak 0x0 : AT ( _end_lma ) {
+ _weak = .;
+ *(.weak)
+ _eweak = .;
+ }
+ _assert = ASSERT ( ( _weak == _eweak ), ".weak is non-zero length" );
/*
* Dispose of the comment and note sections to make the link map
* easier to read
+ *
*/
/DISCARD/ : {
*(.comment)
+ *(.comment.*)
*(.note)
+ *(.note.*)
+ *(.eh_frame)
+ *(.eh_frame.*)
+ *(.rel)
+ *(.rel.*)
}
/*
- * Load address calculations. The slightly obscure nature of the
- * calculations is because ALIGN(x) can only operate on the
- * location counter.
+ * Load address calculations. In older versions of ld, ALIGN()
+ * can operate only on the location counter, so we use that.
+ *
*/
- _max_align = 16;
- _load_addr = 0;
-
- . = _load_addr;
-
- . -= _prefix_link_addr;
- _prefix_load_offset = ALIGN ( _max_align );
- _prefix_load_addr = _prefix_link_addr + _prefix_load_offset;
- _prefix_size = _eprefix - _prefix;
- _prefix_progbits_size = _eprefix_progbits - _prefix;
- . = _prefix_load_addr + _prefix_progbits_size;
-
- . -= _text16_link_addr;
- _text16_load_offset = ALIGN ( _max_align );
- _text16_load_addr = _text16_link_addr + _text16_load_offset;
- _text16_size = _etext16 - _text16;
- _text16_progbits_size = _etext16_progbits - _text16;
- . = _text16_load_addr + _text16_progbits_size;
+ PROVIDE ( _max_align = 16 );
+ . = 0;
- . -= _data16_link_addr;
- _data16_load_offset = ALIGN ( _max_align );
- _data16_load_addr = _data16_link_addr + _data16_load_offset;
- _data16_size = _edata16 - _data16;
- _data16_progbits_size = _edata16_progbits - _data16;
- . = _data16_load_addr + _data16_progbits_size;
+ . = ALIGN ( _max_align );
+ _prefix_lma = .;
+ . += _prefix_filesz;
- . -= _textdata_link_addr;
- _textdata_load_offset = ALIGN ( _max_align );
- _textdata_load_addr = _textdata_link_addr + _textdata_load_offset;
- _textdata_size = _etextdata - _textdata;
- _textdata_progbits_size = _etextdata_progbits - _textdata;
- . = _textdata_load_addr + _textdata_progbits_size;
+ . = ALIGN ( _max_align );
+ _payload_lma = .;
+ _text16_lma = .;
+ . += _text16_filesz;
- _load_size = . - _load_addr;
+ . = ALIGN ( _max_align );
+ _data16_lma = .;
+ . += _data16_filesz;
- . -= _zinfo_link_addr;
- _zinfo_load_offset = ALIGN ( _max_align );
- _zinfo_load_addr = _zinfo_link_addr + _zinfo_load_offset;
- _zinfo_size = _ezinfo - _zinfo;
- _zinfo_progbits_size = _ezinfo_progbits - _zinfo;
- . = _zinfo_load_addr + _zinfo_progbits_size;
+ . = ALIGN ( _max_align );
+ _textdata_lma = .;
+ . += _textdata_filesz;
- _payload_offset = _text16_load_offset;
+ _filesz = .; /* Do not include zinfo block in file size */
- /*
- * Alignment checks. ALIGN() can only operate on the location
- * counter, so we set the location counter to each value we want
- * to check.
- */
-
- . = _prefix_load_addr - _prefix_link_addr;
- _assert = ASSERT ( ( . == ALIGN ( _max_align ) ),
- "_prefix is badly aligned" );
-
- . = _text16_load_addr - _text16_link_addr;
- _assert = ASSERT ( ( . == ALIGN ( _max_align ) ),
- "_text16 is badly aligned" );
+ . = ALIGN ( _max_align );
+ _zinfo_lma = .;
+ . += _zinfo_filesz;
- . = _data16_load_addr - _data16_link_addr;
- _assert = ASSERT ( ( . == ALIGN ( _max_align ) ),
- "_data16 is badly aligned" );
-
- . = _textdata_load_addr - _textdata_link_addr;
- _assert = ASSERT ( ( . == ALIGN ( _max_align ) ),
- "_text is badly aligned" );
+ . = ALIGN ( _max_align );
+ _end_lma = .;
/*
* Values calculated to save code from doing it
+ *
*/
- _prefix_size_pgh = ( ( _prefix_size + 15 ) / 16 );
- _prefix_size_sect = ( ( _prefix_size + 511 ) / 512 );
- _text16_size_pgh = ( ( _text16_size + 15 ) / 16 );
- _data16_size_pgh = ( ( _data16_size + 15 ) / 16 );
+ _prefix_memsz_pgh = ( ( _prefix_memsz + 15 ) / 16 );
+ _prefix_memsz_sect = ( ( _prefix_memsz + 511 ) / 512 );
+ _text16_memsz_pgh = ( ( _text16_memsz + 15 ) / 16 );
+ _data16_memsz_pgh = ( ( _data16_memsz + 15 ) / 16 );
/*
- * Load sizes in paragraphs and sectors. Note that wherever the
- * _load_size variables are used, there must be a corresponding
+ * File size in paragraphs and sectors. Note that wherever the
+ * _filesz variables are used, there must be a corresponding
* .zinfo.fixup section.
+ *
*/
- _load_size_pgh = ( ( _load_size + 15 ) / 16 );
- _load_size_sect = ( ( _load_size + 511 ) / 512 );
+ _filesz_pgh = ( ( _filesz + 15 ) / 16 );
+ _filesz_sect = ( ( _filesz + 511 ) / 512 );
}
diff --git a/gpxe/src/arch/i386/transitions/librm.S b/gpxe/src/arch/i386/transitions/librm.S
index ff4b1d97..7e9fd45d 100644..100755
--- a/gpxe/src/arch/i386/transitions/librm.S
+++ b/gpxe/src/arch/i386/transitions/librm.S
@@ -203,8 +203,8 @@ real_to_prot:
/* Switch to protected mode */
cli
- data32 lgdt gdtr
- data32 lidt idtr
+ data32 lgdt gdtr
+ data32 lidt idtr
movl %cr0, %eax
orb $CR0_PE, %al
movl %eax, %cr0
@@ -316,7 +316,7 @@ p2r_jump_target:
movl %edx, %esp
/* Reset IDTR to the real-mode defaults */
- lidt rm_idtr
+ data32 lidt rm_idtr
/* Return to real-mode address */
data32 ret
@@ -424,8 +424,8 @@ prot_call:
1:
/* Reload GDT and IDT, restore registers and flags and return */
movw %sp, %bp
- lgdt (%bp)
- lidt 8(%bp)
+ data32 lgdt (%bp)
+ data32 lidt 8(%bp)
addw $20, %sp /* also skip %cs and %ss */
popw %ds
popw %es
diff --git a/gpxe/src/arch/i386/transitions/librm_mgmt.c b/gpxe/src/arch/i386/transitions/librm_mgmt.c
index 59b2eabc..50569f8e 100644..100755
--- a/gpxe/src/arch/i386/transitions/librm_mgmt.c
+++ b/gpxe/src/arch/i386/transitions/librm_mgmt.c
@@ -1,45 +1,56 @@
-/*
- * librm: a library for interfacing to real-mode code
- *
- * Michael Brown <mbrown@fensystems.co.uk>
- *
- */
-
-#include <stdint.h>
-#include <librm.h>
-
-/*
- * This file provides functions for managing librm.
- *
- */
-
-/**
- * Allocate space on the real-mode stack and copy data there from a
- * user buffer
- *
- * @v data User buffer
- * @v size Size of stack data
- * @ret sp New value of real-mode stack pointer
- */
-uint16_t copy_user_to_rm_stack ( userptr_t data, size_t size ) {
- userptr_t rm_stack;
- rm_sp -= size;
- rm_stack = real_to_user ( rm_ss, rm_sp );
- memcpy_user ( rm_stack, 0, data, 0, size );
- return rm_sp;
-};
-
-/**
- * Deallocate space on the real-mode stack, optionally copying back
- * data to a user buffer.
- *
- * @v data User buffer
- * @v size Size of stack data
- */
-void remove_user_from_rm_stack ( userptr_t data, size_t size ) {
- if ( data ) {
- userptr_t rm_stack = real_to_user ( rm_ss, rm_sp );
- memcpy_user ( rm_stack, 0, data, 0, size );
- }
- rm_sp += size;
-};
+/*
+ * librm: a library for interfacing to real-mode code
+ *
+ * Michael Brown <mbrown@fensystems.co.uk>
+ *
+ */
+
+#include <stdint.h>
+#include <realmode.h>
+
+/*
+ * This file provides functions for managing librm.
+ *
+ */
+
+/**
+ * Allocate space on the real-mode stack and copy data there from a
+ * user buffer
+ *
+ * @v data User buffer
+ * @v size Size of stack data
+ * @ret sp New value of real-mode stack pointer
+ */
+uint16_t copy_user_to_rm_stack ( userptr_t data, size_t size ) {
+ userptr_t rm_stack;
+ rm_sp -= size;
+ rm_stack = real_to_user ( rm_ss, rm_sp );
+ memcpy_user ( rm_stack, 0, data, 0, size );
+ return rm_sp;
+};
+
+/**
+ * Deallocate space on the real-mode stack, optionally copying back
+ * data to a user buffer.
+ *
+ * @v data User buffer
+ * @v size Size of stack data
+ */
+void remove_user_from_rm_stack ( userptr_t data, size_t size ) {
+ if ( data ) {
+ userptr_t rm_stack = real_to_user ( rm_ss, rm_sp );
+ memcpy_user ( rm_stack, 0, data, 0, size );
+ }
+ rm_sp += size;
+};
+
+PROVIDE_UACCESS_INLINE ( librm, phys_to_user );
+PROVIDE_UACCESS_INLINE ( librm, user_to_phys );
+PROVIDE_UACCESS_INLINE ( librm, virt_to_user );
+PROVIDE_UACCESS_INLINE ( librm, user_to_virt );
+PROVIDE_UACCESS_INLINE ( librm, userptr_add );
+PROVIDE_UACCESS_INLINE ( librm, memcpy_user );
+PROVIDE_UACCESS_INLINE ( librm, memmove_user );
+PROVIDE_UACCESS_INLINE ( librm, memset_user );
+PROVIDE_UACCESS_INLINE ( librm, strlen_user );
+PROVIDE_UACCESS_INLINE ( librm, memchr_user );
diff --git a/gpxe/src/config.h b/gpxe/src/config.h
deleted file mode 100644
index 603604ab..00000000
--- a/gpxe/src/config.h
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * This file defines the configuration for Etherboot.
- *
- * The build system splits this file into several individual header
- * files of the form config/%.h, so that changing one option doesn't
- * necessitate a rebuild of every single object. For this reason, it
- * is important to maintain the strict formatting in this file.
- *
- */
-
-/* @BEGIN general.h
- *
- * Console configuration
- *
- * These options specify the console types that Etherboot will use for
- * interaction with the user.
- *
- */
-
-#define CONSOLE_FIRMWARE /* Default BIOS console */
-#undef CONSOLE_SERIAL /* Serial port */
-#undef CONSOLE_DIRECT_VGA /* Direct access to VGA card */
-#undef CONSOLE_BTEXT /* Who knows what this does? */
-#undef CONSOLE_PC_KBD /* Direct access to PC keyboard */
-
-/* @END general.h */
-
-/* @BEGIN serial.h
- *
- * Serial port configuration
- *
- * These options affect the operation of the serial console. They
- * take effect only if the serial console is included using the
- * CONSOLE_SERIAL option.
- *
- */
-
-#define COMCONSOLE 0x3f8 /* I/O port address */
-
-/* Keep settings from a previous user of the serial port (e.g. lilo or
- * LinuxBIOS), ignoring COMSPEED, COMDATA, COMPARITY and COMSTOP.
- */
-#undef COMPRESERVE
-
-#ifndef COMPRESERVE
-#define COMSPEED 115200 /* Baud rate */
-#define COMDATA 8 /* Data bits */
-#define COMPARITY 0 /* Parity: 0=None, 1=Odd, 2=Even */
-#define COMSTOP 1 /* Stop bits */
-#endif
-
-/* @END serial.h */
-
-/* @BEGIN general.h
- *
- * Timer configuration
- *
- */
-#define TIMER_BIOS /* 18Hz BIOS timer */
-#define TIMER_RDTSC /* CPU TimeStamp Counter timer */
-#define BANNER_TIMEOUT 20 /* Tenths of a second for which the shell
- banner should appear */
-
-/* @END general.h */
-
-/* @BEGIN isa.h
- *
- * ISA probe address configuration
- *
- * You can override the list of addresses that will be probed by any
- * ISA drivers.
- *
- */
-#undef ISA_PROBE_ADDRS /* e.g. 0x200, 0x300 */
-#undef ISA_PROBE_ONLY /* Do not probe any other addresses */
-
-/* @END isa.h */
-
-/* @BEGIN general.h
- *
- * Network protocols
- *
- */
-
-#define NET_PROTO_IPV4 /* IPv4 protocol */
-
-/* @END general.h */
-
-/* @BEGIN general.h
- *
- * Download protocols
- *
- */
-
-#define DOWNLOAD_PROTO_TFTP /* Trivial File Transfer Protocol */
-#define DOWNLOAD_PROTO_NFS /* Network File System */
-#define DOWNLOAD_PROTO_HTTP /* Hypertext Transfer Protocol */
-#define DOWNLOAD_PROTO_HTTPS /* Secure Hypertext Transfer Protocol */
-#define DOWNLOAD_PROTO_FTP /* File 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 */
-
-/* @BEGIN general.h
- *
- * Name resolution modules
- *
- */
-
-#define DNS_RESOLVER /* DNS resolver */
-#undef NMB_RESOLVER /* NMB resolver */
-
-/* @END general.h */
-
-/* @BEGIN general.h
- *
- * Image types
- *
- * Etherboot supports various image formats. Select whichever ones
- * you want to use.
- *
- */
-#undef IMAGE_NBI /* NBI image support */
-#define IMAGE_ELF /* ELF image support */
-#undef IMAGE_FREEBSD /* FreeBSD kernel image support */
-#define IMAGE_MULTIBOOT /* MultiBoot image support */
-#undef IMAGE_AOUT /* a.out image support */
-#undef IMAGE_WINCE /* WinCE image support */
-#define IMAGE_PXE /* PXE image support */
-#define IMAGE_SCRIPT /* gPXE script image support */
-#define IMAGE_BZIMAGE /* Linux bzImage image support */
-#define IMAGE_COMBOOT /* SYSLINUX COMBOOT image support */
-
-/* @END general.h */
-
-/* @BEGIN general.h
- *
- * Command-line commands to include
- *
- */
-#define AUTOBOOT_CMD /* Automatic booting */
-#define NVO_CMD /* Non-volatile option storage commands */
-#define CONFIG_CMD /* Option configuration console */
-#define IFMGMT_CMD /* Interface management commands */
-#define ROUTE_CMD /* Routing table management commands */
-#define IMAGE_CMD /* Image management commands */
-#define DHCP_CMD /* DHCP management commands */
-#define SANBOOT_CMD /* SAN boot commands */
-
-/* @END general.h */
-
-/* @BEGIN general.h
- *
- * Obscure configuration options
- *
- * You probably don't need to touch these.
- *
- */
-
-#undef BUILD_SERIAL /* Include an automatic build serial
- * number. Add "bs" to the list of
- * make targets. For example:
- * "make bin/rtl8139.dsk bs" */
-#undef BUILD_ID /* Include a custom build ID string,
- * e.g "test-foo" */
-#undef NULL_TRAP /* Attempt to catch NULL function calls */
-#undef GDBSERIAL /* Remote GDB debugging over serial */
-#undef GDBUDP /* Remote GDB debugging over UDP
- * (both may be set) */
-
-/* @END general.h */
-
-/* @TRYSOURCE config-local.h */
diff --git a/gpxe/src/config/.gitignore b/gpxe/src/config/.gitignore
index 499ae122..8e94f32f 100644
--- a/gpxe/src/config/.gitignore
+++ b/gpxe/src/config/.gitignore
@@ -1,2 +1 @@
-*.h
.buildserial.*
diff --git a/gpxe/src/config/console.h b/gpxe/src/config/console.h
new file mode 100644
index 00000000..b4ea1dda
--- /dev/null
+++ b/gpxe/src/config/console.h
@@ -0,0 +1,21 @@
+#ifndef CONFIG_CONSOLE_H
+#define CONFIG_CONSOLE_H
+
+/** @file
+ *
+ * Console configuration
+ *
+ * These options specify the console types that Etherboot will use for
+ * interaction with the user.
+ *
+ */
+
+#include <config/defaults.h>
+
+//#define CONSOLE_PCBIOS /* Default BIOS console */
+//#define CONSOLE_SERIAL /* Serial port */
+//#define CONSOLE_DIRECT_VGA /* Direct access to VGA card */
+//#define CONSOLE_BTEXT /* Who knows what this does? */
+//#define CONSOLE_PC_KBD /* Direct access to PC keyboard */
+
+#endif /* CONFIG_CONSOLE_H */
diff --git a/gpxe/src/config/defaults.h b/gpxe/src/config/defaults.h
new file mode 100644
index 00000000..1f55ef3c
--- /dev/null
+++ b/gpxe/src/config/defaults.h
@@ -0,0 +1,8 @@
+#ifndef CONFIG_DEFAULTS_H
+#define CONFIG_DEFAULTS_H
+
+#define CONFIG_DEFAULTS(_platform) <config/defaults/_platform.h>
+
+#include CONFIG_DEFAULTS(PLATFORM)
+
+#endif /* CONFIG_DEFAULTS_H */
diff --git a/gpxe/src/config/defaults/efi.h b/gpxe/src/config/defaults/efi.h
new file mode 100644
index 00000000..d980136a
--- /dev/null
+++ b/gpxe/src/config/defaults/efi.h
@@ -0,0 +1,20 @@
+#ifndef CONFIG_DEFAULTS_EFI_H
+#define CONFIG_DEFAULTS_EFI_H
+
+/** @file
+ *
+ * Configuration defaults for EFI
+ *
+ */
+
+#define UACCESS_EFI
+#define IOAPI_EFI
+#define PCIAPI_EFI
+#define CONSOLE_EFI
+#define TIMER_EFI
+#define NAP_EFIX86
+#define UMALLOC_EFI
+
+#define IMAGE_EFI /* EFI image support */
+
+#endif /* CONFIG_DEFAULTS_EFI_H */
diff --git a/gpxe/src/config/defaults/pcbios.h b/gpxe/src/config/defaults/pcbios.h
new file mode 100644
index 00000000..e1360f53
--- /dev/null
+++ b/gpxe/src/config/defaults/pcbios.h
@@ -0,0 +1,28 @@
+#ifndef CONFIG_DEFAULTS_PCBIOS_H
+#define CONFIG_DEFAULTS_PCBIOS_H
+
+/** @file
+ *
+ * Configuration defaults for PCBIOS
+ *
+ */
+
+#define UACCESS_LIBRM
+#define IOAPI_X86
+#define PCIAPI_PCBIOS
+#define TIMER_PCBIOS
+#define CONSOLE_PCBIOS
+#define NAP_PCBIOS
+#define UMALLOC_MEMTOP
+
+#define IMAGE_ELF /* ELF image support */
+#define IMAGE_MULTIBOOT /* MultiBoot image support */
+#define IMAGE_PXE /* PXE image support */
+#define IMAGE_SCRIPT /* gPXE script image support */
+#define IMAGE_BZIMAGE /* Linux bzImage image support */
+#define IMAGE_COMBOOT /* SYSLINUX COMBOOT image support */
+
+#define SANBOOT_PROTO_ISCSI /* iSCSI protocol */
+#define SANBOOT_PROTO_AOE /* AoE protocol */
+
+#endif /* CONFIG_DEFAULTS_PCBIOS_H */
diff --git a/gpxe/src/config/general.h b/gpxe/src/config/general.h
new file mode 100644
index 00000000..6454b946
--- /dev/null
+++ b/gpxe/src/config/general.h
@@ -0,0 +1,122 @@
+#ifndef CONFIG_GENERAL_H
+#define CONFIG_GENERAL_H
+
+/** @file
+ *
+ * General configuration
+ *
+ */
+
+#include <config/defaults.h>
+
+/*
+ * Branding
+ *
+ * Vendors may use these strings to add their own branding to gPXE.
+ * PRODUCT_NAME is displayed prior to any gPXE branding in startup
+ * messages, and PRODUCT_SHORT_NAME is used where a brief product
+ * label is required (e.g. in BIOS boot selection menus).
+ *
+ * To minimise end-user confusion, it's probably a good idea to either
+ * make PRODUCT_SHORT_NAME a substring of PRODUCT_NAME or leave it as
+ * "gPXE".
+ *
+ */
+#define PRODUCT_NAME ""
+#define PRODUCT_SHORT_NAME "gPXE"
+
+/*
+ * Timer configuration
+ *
+ */
+#define BANNER_TIMEOUT 20 /* Tenths of a second for which the shell
+ banner should appear */
+
+/*
+ * Network protocols
+ *
+ */
+
+#define NET_PROTO_IPV4 /* IPv4 protocol */
+
+/*
+ * Download protocols
+ *
+ */
+
+#define DOWNLOAD_PROTO_TFTP /* Trivial File Transfer Protocol */
+#undef DOWNLOAD_PROTO_NFS /* Network File System */
+#define DOWNLOAD_PROTO_HTTP /* Hypertext Transfer Protocol */
+#undef DOWNLOAD_PROTO_HTTPS /* Secure Hypertext Transfer Protocol */
+#undef DOWNLOAD_PROTO_FTP /* File Transfer Protocol */
+#undef DOWNLOAD_PROTO_TFTM /* Multicast Trivial File Transfer Protocol */
+#undef DOWNLOAD_PROTO_SLAM /* Scalable Local Area Multicast */
+#undef DOWNLOAD_PROTO_FSP /* FSP? */
+
+/*
+ * SAN boot protocols
+ *
+ */
+
+//#undef SANBOOT_PROTO_ISCSI /* iSCSI protocol */
+//#undef SANBOOT_PROTO_AOE /* AoE protocol */
+
+/*
+ * Name resolution modules
+ *
+ */
+
+#define DNS_RESOLVER /* DNS resolver */
+#undef NMB_RESOLVER /* NMB resolver */
+
+/*
+ * Image types
+ *
+ * Etherboot supports various image formats. Select whichever ones
+ * you want to use.
+ *
+ */
+//#define IMAGE_NBI /* NBI image support */
+//#define IMAGE_ELF /* ELF image support */
+//#define IMAGE_FREEBSD /* FreeBSD kernel image support */
+//#define IMAGE_MULTIBOOT /* MultiBoot image support */
+//#define IMAGE_AOUT /* a.out image support */
+//#define IMAGE_WINCE /* WinCE image support */
+//#define IMAGE_PXE /* PXE image support */
+//#define IMAGE_SCRIPT /* gPXE script image support */
+//#define IMAGE_BZIMAGE /* Linux bzImage image support */
+//#define IMAGE_COMBOOT /* SYSLINUX COMBOOT image support */
+//#define IMAGE_EFI /* EFI image support */
+
+/*
+ * Command-line commands to include
+ *
+ */
+#define AUTOBOOT_CMD /* Automatic booting */
+#define NVO_CMD /* Non-volatile option storage commands */
+#define CONFIG_CMD /* Option configuration console */
+#define IFMGMT_CMD /* Interface management commands */
+#define ROUTE_CMD /* Routing table management commands */
+#define IMAGE_CMD /* Image management commands */
+#define DHCP_CMD /* DHCP management commands */
+#define SANBOOT_CMD /* SAN boot commands */
+
+/*
+ * Obscure configuration options
+ *
+ * You probably don't need to touch these.
+ *
+ */
+
+#undef BUILD_SERIAL /* Include an automatic build serial
+ * number. Add "bs" to the list of
+ * make targets. For example:
+ * "make bin/rtl8139.dsk bs" */
+#undef BUILD_ID /* Include a custom build ID string,
+ * e.g "test-foo" */
+#undef NULL_TRAP /* Attempt to catch NULL function calls */
+#undef GDBSERIAL /* Remote GDB debugging over serial */
+#undef GDBUDP /* Remote GDB debugging over UDP
+ * (both may be set) */
+
+#endif /* CONFIG_GENERAL_H */
diff --git a/gpxe/src/config/ioapi.h b/gpxe/src/config/ioapi.h
new file mode 100644
index 00000000..7726a0f0
--- /dev/null
+++ b/gpxe/src/config/ioapi.h
@@ -0,0 +1,15 @@
+#ifndef CONFIG_IOAPI_H
+#define CONFIG_IOAPI_H
+
+/** @file
+ *
+ * I/O API configuration
+ *
+ */
+
+#include <config/defaults.h>
+
+//#undef PCIAPI_PCBIOS /* Access via PCI BIOS */
+//#define PCIAPI_DIRECT /* Direct access via Type 1 accesses */
+
+#endif /* CONFIG_IOAPI_H */
diff --git a/gpxe/src/config/isa.h b/gpxe/src/config/isa.h
new file mode 100644
index 00000000..523be1c0
--- /dev/null
+++ b/gpxe/src/config/isa.h
@@ -0,0 +1,15 @@
+#ifndef CONFIG_ISA_H
+#define CONFIG_ISA_H
+
+/** @file
+ *
+ * ISA probe address configuration
+ *
+ * You can override the list of addresses that will be probed by any
+ * ISA drivers.
+ *
+ */
+#undef ISA_PROBE_ADDRS /* e.g. 0x200, 0x300 */
+#undef ISA_PROBE_ONLY /* Do not probe any other addresses */
+
+#endif /* CONFIG_ISA_H */
diff --git a/gpxe/src/config/nap.h b/gpxe/src/config/nap.h
new file mode 100644
index 00000000..8648d925
--- /dev/null
+++ b/gpxe/src/config/nap.h
@@ -0,0 +1,15 @@
+#ifndef CONFIG_NAP_H
+#define CONFIG_NAP_H
+
+/** @file
+ *
+ * CPU sleeping
+ *
+ */
+
+#include <config/defaults.h>
+
+//#undef NAP_PCBIOS
+//#define NAP_NULL
+
+#endif /* CONFIG_NAP_H */
diff --git a/gpxe/src/config/serial.h b/gpxe/src/config/serial.h
new file mode 100644
index 00000000..984a7a9c
--- /dev/null
+++ b/gpxe/src/config/serial.h
@@ -0,0 +1,28 @@
+#ifndef CONFIG_SERIAL_H
+#define CONFIG_SERIAL_H
+
+/** @file
+ *
+ * Serial port configuration
+ *
+ * These options affect the operation of the serial console. They
+ * take effect only if the serial console is included using the
+ * CONSOLE_SERIAL option.
+ *
+ */
+
+#define COMCONSOLE 0x3f8 /* I/O port address */
+
+/* Keep settings from a previous user of the serial port (e.g. lilo or
+ * LinuxBIOS), ignoring COMSPEED, COMDATA, COMPARITY and COMSTOP.
+ */
+#undef COMPRESERVE
+
+#ifndef COMPRESERVE
+#define COMSPEED 115200 /* Baud rate */
+#define COMDATA 8 /* Data bits */
+#define COMPARITY 0 /* Parity: 0=None, 1=Odd, 2=Even */
+#define COMSTOP 1 /* Stop bits */
+#endif
+
+#endif /* CONFIG_SERIAL_H */
diff --git a/gpxe/src/config/timer.h b/gpxe/src/config/timer.h
new file mode 100644
index 00000000..7c3f3521
--- /dev/null
+++ b/gpxe/src/config/timer.h
@@ -0,0 +1,15 @@
+#ifndef CONFIG_TIMER_H
+#define CONFIG_TIMER_H
+
+/** @file
+ *
+ * Timer configuration.
+ *
+ */
+
+#include <config/defaults.h>
+
+//#undef TIMER_PCBIOS
+//#define TIMER_RDTSC
+
+#endif /* CONFIG_TIMER_H */
diff --git a/gpxe/src/config/umalloc.h b/gpxe/src/config/umalloc.h
new file mode 100644
index 00000000..de4019e5
--- /dev/null
+++ b/gpxe/src/config/umalloc.h
@@ -0,0 +1,12 @@
+#ifndef CONFIG_UMALLOC_H
+#define CONFIG_UMALLOC_H
+
+/** @file
+ *
+ * User memory allocation API configuration
+ *
+ */
+
+#include <config/defaults.h>
+
+#endif /* CONFIG_UMALLOC_H */
diff --git a/gpxe/src/core/config.c b/gpxe/src/core/config.c
index b5624fae..b14d25a8 100644
--- a/gpxe/src/core/config.c
+++ b/gpxe/src/core/config.c
@@ -5,7 +5,8 @@
* your option) any later version.
*/
-#include "config/general.h"
+#include <config/general.h>
+#include <config/console.h>
/*
* Build ID string calculations
@@ -38,19 +39,9 @@
/*
* Drag in all requested console types
*
- * CONSOLE_DUAL sets both CONSOLE_FIRMWARE and CONSOLE_SERIAL for
- * legacy compatibility.
- *
*/
-#ifdef CONSOLE_DUAL
-#undef CONSOLE_FIRMWARE
-#define CONSOLE_FIRMWARE 1
-#undef CONSOLE_SERIAL
-#define CONSOLE_SERIAL 1
-#endif
-
-#ifdef CONSOLE_FIRMWARE
+#ifdef CONSOLE_PCBIOS
REQUIRE_OBJECT ( bios_console );
#endif
#ifdef CONSOLE_SERIAL
@@ -68,15 +59,8 @@ REQUIRE_OBJECT ( pc_kbd );
#ifdef CONSOLE_SYSLOG
REQUIRE_OBJECT ( syslog );
#endif
-
-/*
- * Drag in all requested timers
- */
-#ifdef TIMER_BIOS
-REQUIRE_OBJECT ( timer_bios );
-#endif
-#ifdef TIMER_RDTSC
-REQUIRE_OBJECT ( timer_rdtsc );
+#ifdef CONSOLE_EFI
+REQUIRE_OBJECT ( efi_console );
#endif
/*
@@ -114,6 +98,17 @@ REQUIRE_OBJECT ( slam );
#endif
/*
+ * Drag in all requested SAN boot protocols
+ *
+ */
+#ifdef SANBOOT_PROTO_ISCSI
+REQUIRE_OBJECT ( iscsiboot );
+#endif
+#ifdef SANBOOT_PROTO_AOE
+REQUIRE_OBJECT ( aoeboot );
+#endif
+
+/*
* Drag in all requested resolvers
*
*/
@@ -166,6 +161,9 @@ REQUIRE_OBJECT ( com32_call );
REQUIRE_OBJECT ( com32_wrapper );
REQUIRE_OBJECT ( comboot_resolv );
#endif
+#ifdef IMAGE_EFI
+REQUIRE_OBJECT ( efi_image );
+#endif
/*
* Drag in all requested commands
diff --git a/gpxe/src/core/console.c b/gpxe/src/core/console.c
index 653f689d..c9773f71 100644
--- a/gpxe/src/core/console.c
+++ b/gpxe/src/core/console.c
@@ -1,11 +1,10 @@
#include "stddef.h"
#include "console.h"
#include <gpxe/process.h>
+#include <gpxe/nap.h>
/** @file */
-#include "bios.h"
-
static struct console_driver console_drivers[0]
__table_start ( struct console_driver, console );
static struct console_driver console_drivers_end[0]
@@ -82,9 +81,6 @@ static struct console_driver * has_input ( void ) {
*
* 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.
- *
*/
int getchar ( void ) {
struct console_driver *console;
diff --git a/gpxe/src/core/debug.c b/gpxe/src/core/debug.c
index 09830420..3079cd4c 100644
--- a/gpxe/src/core/debug.c
+++ b/gpxe/src/core/debug.c
@@ -1,7 +1,7 @@
#include <stdio.h>
#include <stdint.h>
#include <stdarg.h>
-#include <io.h>
+#include <gpxe/io.h>
#include <console.h>
void pause ( void ) {
diff --git a/gpxe/src/core/gdbudp.c b/gpxe/src/core/gdbudp.c
index c49a1bca..26feb38a 100644
--- a/gpxe/src/core/gdbudp.c
+++ b/gpxe/src/core/gdbudp.c
@@ -19,7 +19,6 @@
#include <stdio.h>
#include <string.h>
#include <byteswap.h>
-#include <bios.h>
#include <gpxe/iobuf.h>
#include <gpxe/in.h>
#include <gpxe/if_arp.h>
@@ -27,6 +26,7 @@
#include <gpxe/ip.h>
#include <gpxe/udp.h>
#include <gpxe/netdevice.h>
+#include <gpxe/nap.h>
#include <gpxe/gdbstub.h>
#include <gpxe/gdbudp.h>
diff --git a/gpxe/src/core/main.c b/gpxe/src/core/main.c
index d5892261..aaf8111b 100644
--- a/gpxe/src/core/main.c
+++ b/gpxe/src/core/main.c
@@ -20,6 +20,7 @@ Literature dealing with the network protocols:
#include <gpxe/shell.h>
#include <gpxe/shell_banner.h>
#include <usr/autoboot.h>
+#include <config/general.h>
#define NORMAL "\033[0m"
#define BOLD "\033[1m"
@@ -39,8 +40,19 @@ __cdecl int main ( void ) {
initialise();
startup();
- /* Print welcome banner */
- printf ( NORMAL "\n\n\n" BOLD "gPXE " VERSION
+ /*
+ * Print welcome banner
+ *
+ *
+ * If you wish to brand this build of gPXE, please do so by
+ * defining the string PRODUCT_NAME in config/general.h.
+ *
+ * While nothing in the GPL prevents you from removing all
+ * references to gPXE or http://etherboot.org, we prefer you
+ * not to do so.
+ *
+ */
+ printf ( NORMAL "\n\n" PRODUCT_NAME "\n" BOLD "gPXE " VERSION
NORMAL " -- Open Source Boot Firmware -- "
CYAN "http://etherboot.org" NORMAL "\n"
"Features:" );
diff --git a/gpxe/src/core/malloc.c b/gpxe/src/core/malloc.c
index 2d892f42..db7f1bed 100644
--- a/gpxe/src/core/malloc.c
+++ b/gpxe/src/core/malloc.c
@@ -20,7 +20,7 @@
#include <stdint.h>
#include <string.h>
#include <strings.h>
-#include <io.h>
+#include <gpxe/io.h>
#include <gpxe/list.h>
#include <gpxe/init.h>
#include <gpxe/malloc.h>
diff --git a/gpxe/src/core/monojob.c b/gpxe/src/core/monojob.c
index 2c91e132..657bfd7a 100644
--- a/gpxe/src/core/monojob.c
+++ b/gpxe/src/core/monojob.c
@@ -63,7 +63,8 @@ struct job_interface monojob = {
int monojob_wait ( const char *string ) {
int key;
int rc;
- tick_t last_progress_dot;
+ unsigned long last_progress_dot;
+ unsigned long elapsed;
printf ( "%s.", string );
monojob_rc = -EINPROGRESS;
@@ -81,7 +82,8 @@ int monojob_wait ( const char *string ) {
break;
}
}
- if ( ( currticks() - last_progress_dot ) > TICKS_PER_SEC ) {
+ elapsed = ( currticks() - last_progress_dot );
+ if ( elapsed >= TICKS_PER_SEC ) {
printf ( "." );
last_progress_dot = currticks();
}
@@ -89,6 +91,7 @@ int monojob_wait ( const char *string ) {
rc = monojob_rc;
done:
+ job_done ( &monojob, rc );
if ( rc ) {
printf ( " %s\n", strerror ( rc ) );
} else {
diff --git a/gpxe/src/core/null_nap.c b/gpxe/src/core/null_nap.c
new file mode 100644
index 00000000..a3b01eb1
--- /dev/null
+++ b/gpxe/src/core/null_nap.c
@@ -0,0 +1,3 @@
+#include <gpxe/nap.h>
+
+PROVIDE_NAP_INLINE ( null, cpu_nap );
diff --git a/gpxe/src/core/nvo.c b/gpxe/src/core/nvo.c
index 13078022..e5c07d98 100644
--- a/gpxe/src/core/nvo.c
+++ b/gpxe/src/core/nvo.c
@@ -203,7 +203,7 @@ void nvo_init ( struct nvo_block *nvo, struct nvs_device *nvs,
nvo->nvs = nvs;
nvo->fragments = fragments;
settings_init ( &nvo->settings, &nvo_settings_operations, refcnt,
- "nvo" );
+ "nvo", 0 );
}
/**
diff --git a/gpxe/src/core/pc_kbd.c b/gpxe/src/core/pc_kbd.c
index d43357fe..799c8beb 100644
--- a/gpxe/src/core/pc_kbd.c
+++ b/gpxe/src/core/pc_kbd.c
@@ -10,7 +10,7 @@
* yhlu@tyan.com
*/
-#include "io.h"
+#include <gpxe/io.h>
#include "console.h"
static char key_map[][128] = {
diff --git a/gpxe/src/core/process.c b/gpxe/src/core/process.c
index cf931acf..6a687140 100644
--- a/gpxe/src/core/process.c
+++ b/gpxe/src/core/process.c
@@ -79,7 +79,9 @@ void step ( void ) {
list_for_each_entry ( process, &run_queue, list ) {
list_del ( &process->list );
list_add_tail ( &process->list, &run_queue );
+ DBGC2 ( process, "PROCESS %p executing\n", process );
process->step ( process );
+ DBGC2 ( process, "PROCESS %p finished executing\n", process );
break;
}
}
diff --git a/gpxe/src/core/serial.c b/gpxe/src/core/serial.c
index 97640f93..5b3be39c 100644
--- a/gpxe/src/core/serial.c
+++ b/gpxe/src/core/serial.c
@@ -13,7 +13,7 @@
#include "stddef.h"
#include <gpxe/init.h>
-#include "io.h"
+#include <gpxe/io.h>
#include <unistd.h>
#include <gpxe/serial.h>
#include "config/serial.h"
diff --git a/gpxe/src/core/settings.c b/gpxe/src/core/settings.c
index 3e9eb18a..2d9c096e 100644
--- a/gpxe/src/core/settings.c
+++ b/gpxe/src/core/settings.c
@@ -333,6 +333,9 @@ int fetch_setting ( struct settings *settings, struct setting *setting,
struct settings *child;
int ret;
+ /* Avoid returning uninitialised data on error */
+ memset ( data, 0, len );
+
/* NULL settings implies starting at the global settings root */
if ( ! settings )
settings = &settings_root;
@@ -417,20 +420,23 @@ int fetch_ipv4_setting ( struct settings *settings, struct setting *setting,
int fetch_int_setting ( struct settings *settings, struct setting *setting,
long *value ) {
union {
- long value;
uint8_t u8[ sizeof ( long ) ];
int8_t s8[ sizeof ( long ) ];
} buf;
int len;
int i;
- buf.value = 0;
+ /* Avoid returning uninitialised data on error */
+ *value = 0;
+
+ /* Fetch raw (network-ordered, variable-length) setting */
len = fetch_setting ( settings, setting, &buf, sizeof ( buf ) );
if ( len < 0 )
return len;
if ( len > ( int ) sizeof ( buf ) )
return -ERANGE;
+ /* Convert to host-ordered signed long */
*value = ( ( buf.s8[0] >= 0 ) ? 0 : -1L );
for ( i = 0 ; i < len ; i++ ) {
*value = ( ( *value << 8 ) | buf.u8[i] );
@@ -452,10 +458,15 @@ int fetch_uint_setting ( struct settings *settings, struct setting *setting,
long svalue;
int len;
+ /* Avoid returning uninitialised data on error */
+ *value = 0;
+
+ /* Fetch as a signed long */
len = fetch_int_setting ( settings, setting, &svalue );
if ( len < 0 )
return len;
+ /* Mask off sign-extended bits */
*value = ( svalue & ( -1UL >> ( sizeof ( long ) - len ) ) );
return len;
@@ -469,7 +480,7 @@ int fetch_uint_setting ( struct settings *settings, struct setting *setting,
* @ret value Setting value, or zero
*/
long fetch_intz_setting ( struct settings *settings, struct setting *setting ){
- long value = 0;
+ long value;
fetch_int_setting ( settings, setting, &value );
return value;
@@ -484,7 +495,7 @@ long fetch_intz_setting ( struct settings *settings, struct setting *setting ){
*/
unsigned long fetch_uintz_setting ( struct settings *settings,
struct setting *setting ) {
- unsigned long value = 0;
+ unsigned long value;
fetch_uint_setting ( settings, setting, &value );
return value;
@@ -655,6 +666,7 @@ static int parse_setting_name ( const char *name, struct settings **settings,
}
tmp++;
}
+ setting->tag |= (*settings)->tag_magic;
}
/* Identify setting type, if specified */
diff --git a/gpxe/src/core/timer.c b/gpxe/src/core/timer.c
index 4e047ea7..d71e3da1 100644
--- a/gpxe/src/core/timer.c
+++ b/gpxe/src/core/timer.c
@@ -1,7 +1,5 @@
/*
- * core/timer.c
- *
- * Copyright (C) 2007 Alexey Zaytsev <alexey.zaytsev@gmail.com>
+ * Copyright (C) 2008 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
@@ -18,96 +16,25 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <stddef.h>
-#include <assert.h>
-#include <gpxe/timer.h>
-
-static struct timer ts_table[0]
- __table_start ( struct timer, timers );
-static struct timer ts_table_end[0]
- __table_end ( struct timer, timers );
-
-/*
- * This function may be used in custom timer driver.
- *
- * This udelay implementation works well if you've got a
- * fast currticks().
- */
-void generic_currticks_udelay ( unsigned int usecs ) {
- tick_t start;
- tick_t elapsed;
-
- start = currticks();
- do {
- /* xxx: Relax the cpu some way. */
- elapsed = ( currticks() - start );
- } while ( elapsed < usecs );
-}
-
-/**
- * Identify timer source
- *
- * @ret timer Timer source
- */
-static struct timer * timer ( void ) {
- static struct timer *ts = NULL;
-
- /* If we have a timer, use it */
- if ( ts )
- return ts;
-
- /* Scan for a usable timer */
- for ( ts = ts_table ; ts < ts_table_end ; ts++ ) {
- if ( ts->init() == 0 )
- return ts;
- }
-
- /* No timer found; we cannot continue */
- assert ( 0 );
- while ( 1 ) {};
-}
-
-/**
- * Read current time
- *
- * @ret ticks Current time, in ticks
- */
-tick_t currticks ( void ) {
- tick_t ct;
-
- ct = timer()->currticks();
- DBG ( "currticks: %ld.%06ld seconds\n",
- ct / USECS_IN_SEC, ct % USECS_IN_SEC );
-
- return ct;
-}
-
-/**
- * Delay
- *
- * @v usecs Time to delay, in microseconds
- */
-void udelay ( unsigned int usecs ) {
- timer()->udelay ( usecs );
-}
+#include <unistd.h>
/**
- * Delay
+ * Delay for a fixed number of milliseconds
*
- * @v msecs Time to delay, in milliseconds
+ * @v msecs Number of milliseconds for which to delay
*/
-void mdelay ( unsigned int msecs ) {
+void mdelay ( unsigned long msecs ) {
while ( msecs-- )
- udelay ( USECS_IN_MSEC );
+ udelay ( 1000 );
}
/**
- * Delay
+ * Delay for a fixed number of seconds
*
- * @v secs Time to delay, in seconds
+ * @v secs Number of seconds for which to delay
*/
unsigned int sleep ( unsigned int secs ) {
while ( secs-- )
- mdelay ( MSECS_IN_SEC );
+ mdelay ( 1000 );
return 0;
}
diff --git a/gpxe/src/core/uri.c b/gpxe/src/core/uri.c
index cf2b071d..7bb46da0 100644
--- a/gpxe/src/core/uri.c
+++ b/gpxe/src/core/uri.c
@@ -92,8 +92,12 @@ struct uri * parse_uri ( const char *uri_string ) {
uri->fragment = tmp;
}
- /* Identify absolute/relative URI */
- if ( ( tmp = strchr ( raw, ':' ) ) ) {
+ /* Identify absolute/relative URI. We ignore schemes that are
+ * apparently only a single character long, since otherwise we
+ * misinterpret a DOS-style path name ("C:\path\to\file") as a
+ * URI with scheme="C",opaque="\path\to\file".
+ */
+ if ( ( tmp = strchr ( raw, ':' ) ) && ( tmp > ( raw + 1 ) ) ) {
/* Absolute URI: identify hierarchical/opaque */
uri->scheme = raw;
*(tmp++) = '\0';
diff --git a/gpxe/src/crypto/cryptoLayer.h b/gpxe/src/crypto/cryptoLayer.h
index 28ce97bc..d2e10f2f 100644
--- a/gpxe/src/crypto/cryptoLayer.h
+++ b/gpxe/src/crypto/cryptoLayer.h
@@ -14,7 +14,7 @@
#include <ctype.h>
#include <assert.h>
#include <byteswap.h>
-#include <gpxe/bitops.h>
+#include <gpxe/rotate.h>
#include <gpxe/crypto.h>
/* Drag in pscrypto.h */
diff --git a/gpxe/src/drivers/bitbash/i2c_bit.c b/gpxe/src/drivers/bitbash/i2c_bit.c
index a3af610b..b85057af 100644
--- a/gpxe/src/drivers/bitbash/i2c_bit.c
+++ b/gpxe/src/drivers/bitbash/i2c_bit.c
@@ -19,6 +19,7 @@
#include <stddef.h>
#include <stdint.h>
#include <errno.h>
+#include <string.h>
#include <assert.h>
#include <unistd.h>
#include <gpxe/bitbash.h>
@@ -49,6 +50,7 @@ static void i2c_delay ( void ) {
* @v state New state of SCL
*/
static void setscl ( struct bit_basher *basher, int state ) {
+ DBG2 ( "%c", ( state ? '/' : '\\' ) );
write_bit ( basher, I2C_BIT_SCL, state );
i2c_delay();
}
@@ -60,6 +62,7 @@ static void setscl ( struct bit_basher *basher, int state ) {
* @v state New state of SDA
*/
static void setsda ( struct bit_basher *basher, int state ) {
+ DBG2 ( "%c", ( state ? '1' : '0' ) );
write_bit ( basher, I2C_BIT_SDA, state );
i2c_delay();
}
@@ -71,7 +74,10 @@ static void setsda ( struct bit_basher *basher, int state ) {
* @ret state State of SDA
*/
static int getsda ( struct bit_basher *basher ) {
- return read_bit ( basher, I2C_BIT_SDA );
+ int state;
+ state = read_bit ( basher, I2C_BIT_SDA );
+ DBG2 ( "%c", ( state ? '+' : '-' ) );
+ return state;
}
/**
@@ -137,15 +143,20 @@ static void i2c_stop ( struct bit_basher *basher ) {
*/
static int i2c_send_byte ( struct bit_basher *basher, uint8_t byte ) {
int i;
-
+ int ack;
+
/* Send byte */
+ DBG2 ( "[send %02x]", byte );
for ( i = 8 ; i ; i-- ) {
i2c_send_bit ( basher, byte & 0x80 );
byte <<= 1;
}
/* Check for acknowledgement from slave */
- return ( i2c_recv_bit ( basher ) == 0 ? 0 : -EIO );
+ ack = ( i2c_recv_bit ( basher ) == 0 );
+ DBG2 ( "%s", ( ack ? "[acked]" : "[not acked]" ) );
+
+ return ( ack ? 0 : -EIO );
}
/**
@@ -157,19 +168,20 @@ static int i2c_send_byte ( struct bit_basher *basher, uint8_t byte ) {
* Receives a byte via the I2C bus and sends NACK to the slave device.
*/
static uint8_t i2c_recv_byte ( struct bit_basher *basher ) {
- uint8_t value = 0;
+ uint8_t byte = 0;
int i;
/* Receive byte */
for ( i = 8 ; i ; i-- ) {
- value <<= 1;
- value |= ( i2c_recv_bit ( basher ) & 0x1 );
+ byte <<= 1;
+ byte |= ( i2c_recv_bit ( basher ) & 0x1 );
}
/* Send NACK */
i2c_send_bit ( basher, 1 );
- return value;
+ DBG2 ( "[rcvd %02x]", byte );
+ return byte;
}
/**
@@ -177,30 +189,29 @@ static uint8_t i2c_recv_byte ( struct bit_basher *basher ) {
*
* @v basher Bit-bashing interface
* @v i2cdev I2C device
+ * @v offset Starting offset within the device
* @v direction I2C_READ or I2C_WRITE
* @ret rc Return status code
*/
static int i2c_select ( struct bit_basher *basher, struct i2c_device *i2cdev,
- unsigned int direction ) {
+ unsigned int offset, unsigned int direction ) {
unsigned int address;
+ int shift;
+ unsigned int byte;
int rc;
i2c_start ( basher );
- /* First byte of the address */
- address = i2cdev->address;
- if ( i2cdev->tenbit ) {
- address |= I2C_TENBIT_ADDRESS;
- address >>= 8;
- }
- if ( ( rc = i2c_send_byte ( basher,
- ( ( address << 1 ) | direction ) ) ) != 0 )
- return rc;
+ /* Calculate address to appear on bus */
+ address = ( ( ( i2cdev->dev_addr |
+ ( offset >> ( 8 * i2cdev->word_addr_len ) ) ) << 1 )
+ | direction );
- /* Second byte of the address (10-bit addresses only) */
- if ( i2cdev->tenbit ) {
- if ( ( rc = i2c_send_byte ( basher,
- ( i2cdev->address & 0xff ) ) ) !=0)
+ /* Send address a byte at a time */
+ for ( shift = ( 8 * ( i2cdev->dev_addr_len - 1 ) ) ;
+ shift >= 0 ; shift -= 8 ) {
+ byte = ( ( address >> shift ) & 0xff );
+ if ( ( rc = i2c_send_byte ( basher, byte ) ) != 0 )
return rc;
}
@@ -208,6 +219,46 @@ static int i2c_select ( struct bit_basher *basher, struct i2c_device *i2cdev,
}
/**
+ * Reset I2C bus
+ *
+ * @v basher Bit-bashing interface
+ * @ret rc Return status code
+ *
+ * i2c devices often don't have a reset line, so even a reboot or
+ * system power cycle is sometimes not enough to bring them back to a
+ * known state.
+ */
+static int i2c_reset ( struct bit_basher *basher ) {
+ unsigned int i;
+ int sda;
+
+ /* Clock through several cycles, waiting for an opportunity to
+ * pull SDA low while SCL is high (which creates a start
+ * condition).
+ */
+ setscl ( basher, 0 );
+ setsda ( basher, 1 );
+ for ( i = 0 ; i < I2C_RESET_MAX_CYCLES ; i++ ) {
+ setscl ( basher, 1 );
+ sda = getsda ( basher );
+ if ( sda ) {
+ /* Now that the device will see a start, issue it */
+ i2c_start ( basher );
+ /* Stop the bus to leave it in a known good state */
+ i2c_stop ( basher );
+ DBGC ( basher, "I2CBIT %p reset after %d attempts\n",
+ basher, ( i + 1 ) );
+ return 0;
+ }
+ setscl ( basher, 0 );
+ }
+
+ DBGC ( basher, "I2CBIT %p could not reset after %d attempts\n",
+ basher, i );
+ return -ETIMEDOUT;
+}
+
+/**
* Read data from I2C device via bit-bashing interface
*
* @v i2c I2C interface
@@ -228,12 +279,14 @@ static int i2c_bit_read ( struct i2c_interface *i2c,
struct bit_basher *basher = &i2cbit->basher;
int rc = 0;
- DBG ( "Reading from I2C device %x: ", i2cdev->address );
+ DBGC ( basher, "I2CBIT %p reading from device %x: ",
+ basher, i2cdev->dev_addr );
- while ( 1 ) {
+ for ( ; ; data++, offset++ ) {
/* Select device for writing */
- if ( ( rc = i2c_select ( basher, i2cdev, I2C_WRITE ) ) != 0 )
+ if ( ( rc = i2c_select ( basher, i2cdev, offset,
+ I2C_WRITE ) ) != 0 )
break;
/* Abort at end of data */
@@ -241,19 +294,20 @@ static int i2c_bit_read ( struct i2c_interface *i2c,
break;
/* Select offset */
- if ( ( rc = i2c_send_byte ( basher, offset++ ) ) != 0 )
+ if ( ( rc = i2c_send_byte ( basher, offset ) ) != 0 )
break;
/* Select device for reading */
- if ( ( rc = i2c_select ( basher, i2cdev, I2C_READ ) ) != 0 )
+ if ( ( rc = i2c_select ( basher, i2cdev, offset,
+ I2C_READ ) ) != 0 )
break;
/* Read byte */
- *data++ = i2c_recv_byte ( basher );
- DBG ( "%02x ", *(data - 1) );
+ *data = i2c_recv_byte ( basher );
+ DBGC ( basher, "%02x ", *data );
}
- DBG ( "%s\n", ( rc ? "failed" : "" ) );
+ DBGC ( basher, "%s\n", ( rc ? "failed" : "" ) );
i2c_stop ( basher );
return rc;
}
@@ -279,12 +333,14 @@ static int i2c_bit_write ( struct i2c_interface *i2c,
struct bit_basher *basher = &i2cbit->basher;
int rc = 0;
- DBG ( "Writing to I2C device %x: ", i2cdev->address );
+ DBGC ( basher, "I2CBIT %p writing to device %x: ",
+ basher, i2cdev->dev_addr );
- while ( 1 ) {
+ for ( ; ; data++, offset++ ) {
/* Select device for writing */
- if ( ( rc = i2c_select ( basher, i2cdev, I2C_WRITE ) ) != 0 )
+ if ( ( rc = i2c_select ( basher, i2cdev, offset,
+ I2C_WRITE ) ) != 0 )
break;
/* Abort at end of data */
@@ -292,16 +348,16 @@ static int i2c_bit_write ( struct i2c_interface *i2c,
break;
/* Select offset */
- if ( ( rc = i2c_send_byte ( basher, offset++ ) ) != 0 )
+ if ( ( rc = i2c_send_byte ( basher, offset ) ) != 0 )
break;
/* Write data to device */
- DBG ( "%02x ", *data );
- if ( ( rc = i2c_send_byte ( basher, *data++ ) ) != 0 )
+ DBGC ( basher, "%02x ", *data );
+ if ( ( rc = i2c_send_byte ( basher, *data ) ) != 0 )
break;
}
- DBG ( "%s\n", ( rc ? "failed" : "" ) );
+ DBGC ( basher, "%s\n", ( rc ? "failed" : "" ) );
i2c_stop ( basher );
return rc;
}
@@ -310,13 +366,26 @@ static int i2c_bit_write ( struct i2c_interface *i2c,
* Initialise I2C bit-bashing interface
*
* @v i2cbit I2C bit-bashing interface
+ * @v bash_op Bit-basher operations
*/
-void init_i2c_bit_basher ( struct i2c_bit_basher *i2cbit ) {
+int init_i2c_bit_basher ( struct i2c_bit_basher *i2cbit,
+ struct bit_basher_operations *bash_op ) {
struct bit_basher *basher = &i2cbit->basher;
-
+ int rc;
+
+ /* Initialise data structures */
+ basher->op = bash_op;
assert ( basher->op->read != NULL );
assert ( basher->op->write != NULL );
i2cbit->i2c.read = i2c_bit_read;
i2cbit->i2c.write = i2c_bit_write;
- i2c_stop ( basher );
+
+ /* Reset I2C bus */
+ if ( ( rc = i2c_reset ( basher ) ) != 0 ) {
+ DBGC ( basher, "I2CBIT %p could not reset I2C bus: %s\n",
+ basher, strerror ( rc ) );
+ return rc;
+ }
+
+ return 0;
}
diff --git a/gpxe/src/drivers/bus/eisa.c b/gpxe/src/drivers/bus/eisa.c
index ee03df3a..d9e42359 100644
--- a/gpxe/src/drivers/bus/eisa.c
+++ b/gpxe/src/drivers/bus/eisa.c
@@ -3,7 +3,7 @@
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
-#include <io.h>
+#include <gpxe/io.h>
#include <unistd.h>
#include <gpxe/eisa.h>
diff --git a/gpxe/src/drivers/bus/isa.c b/gpxe/src/drivers/bus/isa.c
index a4105fd0..fa5def54 100644
--- a/gpxe/src/drivers/bus/isa.c
+++ b/gpxe/src/drivers/bus/isa.c
@@ -3,7 +3,7 @@
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
-#include <io.h>
+#include <gpxe/io.h>
#include <gpxe/isa.h>
/*
@@ -49,9 +49,9 @@ static isa_probe_addr_t isa_extra_probe_addrs[] = {
(driver)->probe_addrs[(ioidx)] )
static struct isa_driver isa_drivers[0]
- __table_start ( struct isa_driver, isa_driver );
+ __table_start ( struct isa_driver, isa_drivers );
static struct isa_driver isa_drivers_end[0]
- __table_end ( struct isa_driver, isa_driver );
+ __table_end ( struct isa_driver, isa_drivers );
static void isabus_remove ( struct root_device *rootdev );
diff --git a/gpxe/src/drivers/bus/isapnp.c b/gpxe/src/drivers/bus/isapnp.c
index f4968eb1..0915a92b 100644
--- a/gpxe/src/drivers/bus/isapnp.c
+++ b/gpxe/src/drivers/bus/isapnp.c
@@ -60,7 +60,7 @@
#include <string.h>
#include <stdio.h>
#include <errno.h>
-#include <io.h>
+#include <gpxe/io.h>
#include <unistd.h>
#include <gpxe/isapnp.h>
diff --git a/gpxe/src/drivers/bus/mca.c b/gpxe/src/drivers/bus/mca.c
index eb7b7e39..e9233813 100644
--- a/gpxe/src/drivers/bus/mca.c
+++ b/gpxe/src/drivers/bus/mca.c
@@ -10,7 +10,7 @@
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
-#include <io.h>
+#include <gpxe/io.h>
#include <gpxe/mca.h>
static struct mca_driver mca_drivers[0]
diff --git a/gpxe/src/drivers/infiniband/arbel.c b/gpxe/src/drivers/infiniband/arbel.c
index 1b55131b..e516031b 100644
--- a/gpxe/src/drivers/infiniband/arbel.c
+++ b/gpxe/src/drivers/infiniband/arbel.c
@@ -33,6 +33,7 @@
#include <gpxe/iobuf.h>
#include <gpxe/netdevice.h>
#include <gpxe/infiniband.h>
+#include <gpxe/ib_smc.h>
#include "arbel.h"
/**
@@ -484,6 +485,50 @@ arbel_cmd_map_fa ( struct arbel *arbel,
/***************************************************************************
*
+ * MAD operations
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Issue management datagram
+ *
+ * @v ibdev Infiniband device
+ * @v mad Management datagram
+ * @ret rc Return status code
+ */
+static int arbel_mad ( struct ib_device *ibdev, union ib_mad *mad ) {
+ struct arbel *arbel = ib_get_drvdata ( ibdev );
+ union arbelprm_mad mad_ifc;
+ int rc;
+
+ linker_assert ( sizeof ( *mad ) == sizeof ( mad_ifc.mad ),
+ mad_size_mismatch );
+
+ /* Copy in request packet */
+ memcpy ( &mad_ifc.mad, mad, sizeof ( mad_ifc.mad ) );
+
+ /* Issue MAD */
+ if ( ( rc = arbel_cmd_mad_ifc ( arbel, ibdev->port,
+ &mad_ifc ) ) != 0 ) {
+ DBGC ( arbel, "Arbel %p could not issue MAD IFC: %s\n",
+ arbel, strerror ( rc ) );
+ return rc;
+ }
+
+ /* Copy out reply packet */
+ memcpy ( mad, &mad_ifc.mad, sizeof ( *mad ) );
+
+ if ( mad->hdr.status != 0 ) {
+ DBGC ( arbel, "Arbel %p MAD IFC status %04x\n",
+ arbel, ntohs ( mad->hdr.status ) );
+ return -EIO;
+ }
+ return 0;
+}
+
+/***************************************************************************
+ *
* Completion queue operations
*
***************************************************************************
@@ -1006,7 +1051,7 @@ static int arbel_post_send ( struct ib_device *ibdev,
ud_address_vector.pd, ARBEL_GLOBAL_PD,
ud_address_vector.port_number, ibdev->port );
MLX_FILL_2 ( &wqe->ud, 1,
- ud_address_vector.rlid, av->dlid,
+ ud_address_vector.rlid, av->lid,
ud_address_vector.g, av->gid_present );
MLX_FILL_2 ( &wqe->ud, 2,
ud_address_vector.max_stat_rate,
@@ -1015,7 +1060,7 @@ static int arbel_post_send ( struct ib_device *ibdev,
MLX_FILL_1 ( &wqe->ud, 3, ud_address_vector.sl, av->sl );
gid = ( av->gid_present ? &av->gid : &arbel_no_gid );
memcpy ( &wqe->ud.u.dwords[4], gid, sizeof ( *gid ) );
- MLX_FILL_1 ( &wqe->ud, 8, destination_qp, av->dest_qp );
+ MLX_FILL_1 ( &wqe->ud, 8, destination_qp, av->qpn );
MLX_FILL_1 ( &wqe->ud, 9, q_key, av->qkey );
MLX_FILL_1 ( &wqe->data[0], 0, byte_count, iob_len ( iobuf ) );
MLX_FILL_1 ( &wqe->data[0], 1, l_key, arbel->reserved_lkey );
@@ -1106,17 +1151,12 @@ static int arbel_post_recv ( struct ib_device *ibdev,
* @v ibdev Infiniband device
* @v cq Completion queue
* @v cqe Hardware completion queue entry
- * @v complete_send Send completion handler
- * @v complete_recv Receive completion handler
* @ret rc Return status code
*/
static int arbel_complete ( struct ib_device *ibdev,
struct ib_completion_queue *cq,
- union arbelprm_completion_entry *cqe,
- ib_completer_t complete_send,
- ib_completer_t complete_recv ) {
+ union arbelprm_completion_entry *cqe ) {
struct arbel *arbel = ib_get_drvdata ( ibdev );
- struct ib_completion completion;
struct ib_work_queue *wq;
struct ib_queue_pair *qp;
struct arbel_queue_pair *arbel_qp;
@@ -1124,16 +1164,17 @@ static int arbel_complete ( struct ib_device *ibdev,
struct arbel_recv_work_queue *arbel_recv_wq;
struct arbelprm_recv_wqe *recv_wqe;
struct io_buffer *iobuf;
- ib_completer_t complete;
+ struct ib_address_vector av;
+ struct ib_global_route_header *grh;
unsigned int opcode;
unsigned long qpn;
int is_send;
unsigned long wqe_adr;
unsigned int wqe_idx;
+ size_t len;
int rc = 0;
/* Parse completion */
- memset ( &completion, 0, sizeof ( completion ) );
qpn = MLX_GET ( &cqe->normal, my_qpn );
is_send = MLX_GET ( &cqe->normal, s );
wqe_adr = ( MLX_GET ( &cqe->normal, wqe_adr ) << 6 );
@@ -1141,9 +1182,8 @@ static int arbel_complete ( struct ib_device *ibdev,
if ( opcode >= ARBEL_OPCODE_RECV_ERROR ) {
/* "s" field is not valid for error opcodes */
is_send = ( opcode == ARBEL_OPCODE_SEND_ERROR );
- completion.syndrome = MLX_GET ( &cqe->error, syndrome );
- DBGC ( arbel, "Arbel %p CPN %lx syndrome %x vendor %lx\n",
- arbel, cq->cqn, completion.syndrome,
+ DBGC ( arbel, "Arbel %p CPN %lx syndrome %lx vendor %lx\n",
+ arbel, cq->cqn, MLX_GET ( &cqe->error, syndrome ),
MLX_GET ( &cqe->error, vendor_code ) );
rc = -EIO;
/* Don't return immediately; propagate error to completer */
@@ -1181,9 +1221,12 @@ static int arbel_complete ( struct ib_device *ibdev,
}
wq->iobufs[wqe_idx] = NULL;
- /* Fill in length for received packets */
- if ( ! is_send ) {
- completion.len = MLX_GET ( &cqe->normal, byte_cnt );
+ if ( is_send ) {
+ /* Hand off to completion handler */
+ ib_complete_send ( ibdev, qp, iobuf, rc );
+ } else {
+ /* Set received length */
+ len = MLX_GET ( &cqe->normal, byte_cnt );
recv_wqe = &arbel_recv_wq->wqe[wqe_idx].recv;
assert ( MLX_GET ( &recv_wqe->data[0], local_address_l ) ==
virt_to_bus ( iobuf->data ) );
@@ -1192,18 +1235,22 @@ static int arbel_complete ( struct ib_device *ibdev,
MLX_FILL_1 ( &recv_wqe->data[0], 0, byte_count, 0 );
MLX_FILL_1 ( &recv_wqe->data[0], 1,
l_key, ARBEL_INVALID_LKEY );
- if ( completion.len > iob_tailroom ( iobuf ) ) {
- DBGC ( arbel, "Arbel %p CQN %lx QPN %lx IDX %x "
- "overlength received packet length %zd\n",
- arbel, cq->cqn, qpn, wqe_idx, completion.len );
- return -EIO;
- }
+ assert ( len <= iob_tailroom ( iobuf ) );
+ iob_put ( iobuf, len );
+ assert ( iob_len ( iobuf ) >= sizeof ( *grh ) );
+ grh = iobuf->data;
+ iob_pull ( iobuf, sizeof ( *grh ) );
+ /* Construct address vector */
+ memset ( &av, 0, sizeof ( av ) );
+ av.qpn = MLX_GET ( &cqe->normal, rqpn );
+ av.lid = MLX_GET ( &cqe->normal, rlid );
+ av.sl = MLX_GET ( &cqe->normal, sl );
+ av.gid_present = MLX_GET ( &cqe->normal, g );
+ memcpy ( &av.gid, &grh->sgid, sizeof ( av.gid ) );
+ /* Hand off to completion handler */
+ ib_complete_recv ( ibdev, qp, &av, iobuf, rc );
}
- /* Pass off to caller's completion handler */
- complete = ( is_send ? complete_send : complete_recv );
- complete ( ibdev, qp, &completion, iobuf );
-
return rc;
}
@@ -1212,13 +1259,9 @@ static int arbel_complete ( struct ib_device *ibdev,
*
* @v ibdev Infiniband device
* @v cq Completion queue
- * @v complete_send Send completion handler
- * @v complete_recv Receive completion handler
*/
static void arbel_poll_cq ( struct ib_device *ibdev,
- struct ib_completion_queue *cq,
- ib_completer_t complete_send,
- ib_completer_t complete_recv ) {
+ struct ib_completion_queue *cq ) {
struct arbel *arbel = ib_get_drvdata ( ibdev );
struct arbel_completion_queue *arbel_cq = ib_cq_get_drvdata ( cq );
struct arbelprm_cq_ci_db_record *ci_db_rec;
@@ -1236,8 +1279,7 @@ static void arbel_poll_cq ( struct ib_device *ibdev,
}
/* Handle completion */
- if ( ( rc = arbel_complete ( ibdev, cq, cqe, complete_send,
- complete_recv ) ) != 0 ) {
+ if ( ( rc = arbel_complete ( ibdev, cq, cqe ) ) != 0 ) {
DBGC ( arbel, "Arbel %p failed to complete: %s\n",
arbel, strerror ( rc ) );
DBGC_HD ( arbel, cqe, sizeof ( *cqe ) );
@@ -1397,6 +1439,9 @@ static void arbel_event_port_state_change ( struct arbel *arbel,
return;
}
+ /* Update MAD parameters */
+ ib_smc_update ( arbel->ibdev[port], arbel_mad );
+
/* Notify Infiniband core of link state change */
ib_link_state_changed ( arbel->ibdev[port] );
}
@@ -1486,6 +1531,9 @@ static int arbel_open ( struct ib_device *ibdev ) {
return rc;
}
+ /* Update MAD parameters */
+ ib_smc_update ( ibdev, arbel_mad );
+
return 0;
}
@@ -1601,51 +1649,6 @@ static void arbel_mcast_detach ( struct ib_device *ibdev,
}
}
-/***************************************************************************
- *
- * MAD operations
- *
- ***************************************************************************
- */
-
-/**
- * Issue management datagram
- *
- * @v ibdev Infiniband device
- * @v mad Management datagram
- * @v len Length of management datagram
- * @ret rc Return status code
- */
-static int arbel_mad ( struct ib_device *ibdev, struct ib_mad_hdr *mad,
- size_t len ) {
- struct arbel *arbel = ib_get_drvdata ( ibdev );
- union arbelprm_mad mad_ifc;
- int rc;
-
- /* Copy in request packet */
- memset ( &mad_ifc, 0, sizeof ( mad_ifc ) );
- assert ( len <= sizeof ( mad_ifc.mad ) );
- memcpy ( &mad_ifc.mad, mad, len );
-
- /* Issue MAD */
- if ( ( rc = arbel_cmd_mad_ifc ( arbel, ibdev->port,
- &mad_ifc ) ) != 0 ) {
- DBGC ( arbel, "Arbel %p could not issue MAD IFC: %s\n",
- arbel, strerror ( rc ) );
- return rc;
- }
-
- /* Copy out reply packet */
- memcpy ( mad, &mad_ifc.mad, len );
-
- if ( mad->status != 0 ) {
- DBGC ( arbel, "Arbel %p MAD IFC status %04x\n",
- arbel, ntohs ( mad->status ) );
- return -EIO;
- }
- return 0;
-}
-
/** Arbel Infiniband operations */
static struct ib_device_operations arbel_ib_operations = {
.create_cq = arbel_create_cq,
@@ -1661,7 +1664,6 @@ static struct ib_device_operations arbel_ib_operations = {
.close = arbel_close,
.mcast_attach = arbel_mcast_attach,
.mcast_detach = arbel_mcast_detach,
- .mad = arbel_mad,
};
/***************************************************************************
diff --git a/gpxe/src/drivers/infiniband/hermon.c b/gpxe/src/drivers/infiniband/hermon.c
index 3ca60033..01eab396 100644
--- a/gpxe/src/drivers/infiniband/hermon.c
+++ b/gpxe/src/drivers/infiniband/hermon.c
@@ -31,6 +31,7 @@
#include <gpxe/iobuf.h>
#include <gpxe/netdevice.h>
#include <gpxe/infiniband.h>
+#include <gpxe/ib_smc.h>
#include "hermon.h"
/**
@@ -610,6 +611,50 @@ static void hermon_free_mtt ( struct hermon *hermon,
/***************************************************************************
*
+ * MAD operations
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Issue management datagram
+ *
+ * @v ibdev Infiniband device
+ * @v mad Management datagram
+ * @ret rc Return status code
+ */
+static int hermon_mad ( struct ib_device *ibdev, union ib_mad *mad ) {
+ struct hermon *hermon = ib_get_drvdata ( ibdev );
+ union hermonprm_mad mad_ifc;
+ int rc;
+
+ linker_assert ( sizeof ( *mad ) == sizeof ( mad_ifc.mad ),
+ mad_size_mismatch );
+
+ /* Copy in request packet */
+ memcpy ( &mad_ifc.mad, mad, sizeof ( mad_ifc.mad ) );
+
+ /* Issue MAD */
+ if ( ( rc = hermon_cmd_mad_ifc ( hermon, ibdev->port,
+ &mad_ifc ) ) != 0 ) {
+ DBGC ( hermon, "Hermon %p could not issue MAD IFC: %s\n",
+ hermon, strerror ( rc ) );
+ return rc;
+ }
+
+ /* Copy out reply packet */
+ memcpy ( mad, &mad_ifc.mad, sizeof ( *mad ) );
+
+ if ( mad->hdr.status != 0 ) {
+ DBGC ( hermon, "Hermon %p MAD IFC status %04x\n",
+ hermon, ntohs ( mad->hdr.status ) );
+ return -EIO;
+ }
+ return 0;
+}
+
+/***************************************************************************
+ *
* Completion queue operations
*
***************************************************************************
@@ -1015,7 +1060,7 @@ static int hermon_post_send ( struct ib_device *ibdev,
ud_address_vector.pd, HERMON_GLOBAL_PD,
ud_address_vector.port_number, ibdev->port );
MLX_FILL_2 ( &wqe->ud, 1,
- ud_address_vector.rlid, av->dlid,
+ ud_address_vector.rlid, av->lid,
ud_address_vector.g, av->gid_present );
MLX_FILL_1 ( &wqe->ud, 2,
ud_address_vector.max_stat_rate,
@@ -1024,7 +1069,7 @@ static int hermon_post_send ( struct ib_device *ibdev,
MLX_FILL_1 ( &wqe->ud, 3, ud_address_vector.sl, av->sl );
gid = ( av->gid_present ? &av->gid : &hermon_no_gid );
memcpy ( &wqe->ud.u.dwords[4], gid, sizeof ( *gid ) );
- MLX_FILL_1 ( &wqe->ud, 8, destination_qp, av->dest_qp );
+ MLX_FILL_1 ( &wqe->ud, 8, destination_qp, av->qpn );
MLX_FILL_1 ( &wqe->ud, 9, q_key, av->qkey );
MLX_FILL_1 ( &wqe->data[0], 0, byte_count, iob_len ( iobuf ) );
MLX_FILL_1 ( &wqe->data[0], 1, l_key, hermon->reserved_lkey );
@@ -1101,39 +1146,34 @@ static int hermon_post_recv ( struct ib_device *ibdev,
* @v ibdev Infiniband device
* @v cq Completion queue
* @v cqe Hardware completion queue entry
- * @v complete_send Send completion handler
- * @v complete_recv Receive completion handler
* @ret rc Return status code
*/
static int hermon_complete ( struct ib_device *ibdev,
struct ib_completion_queue *cq,
- union hermonprm_completion_entry *cqe,
- ib_completer_t complete_send,
- ib_completer_t complete_recv ) {
+ union hermonprm_completion_entry *cqe ) {
struct hermon *hermon = ib_get_drvdata ( ibdev );
- struct ib_completion completion;
struct ib_work_queue *wq;
struct ib_queue_pair *qp;
struct hermon_queue_pair *hermon_qp;
struct io_buffer *iobuf;
- ib_completer_t complete;
+ struct ib_address_vector av;
+ struct ib_global_route_header *grh;
unsigned int opcode;
unsigned long qpn;
int is_send;
unsigned int wqe_idx;
+ size_t len;
int rc = 0;
/* Parse completion */
- memset ( &completion, 0, sizeof ( completion ) );
qpn = MLX_GET ( &cqe->normal, qpn );
is_send = MLX_GET ( &cqe->normal, s_r );
opcode = MLX_GET ( &cqe->normal, opcode );
if ( opcode >= HERMON_OPCODE_RECV_ERROR ) {
/* "s" field is not valid for error opcodes */
is_send = ( opcode == HERMON_OPCODE_SEND_ERROR );
- completion.syndrome = MLX_GET ( &cqe->error, syndrome );
- DBGC ( hermon, "Hermon %p CQN %lx syndrome %x vendor %lx\n",
- hermon, cq->cqn, completion.syndrome,
+ DBGC ( hermon, "Hermon %p CQN %lx syndrome %lx vendor %lx\n",
+ hermon, cq->cqn, MLX_GET ( &cqe->error, syndrome ),
MLX_GET ( &cqe->error, vendor_error_syndrome ) );
rc = -EIO;
/* Don't return immediately; propagate error to completer */
@@ -1160,21 +1200,28 @@ static int hermon_complete ( struct ib_device *ibdev,
}
wq->iobufs[wqe_idx] = NULL;
- /* Fill in length for received packets */
- if ( ! is_send ) {
- completion.len = MLX_GET ( &cqe->normal, byte_cnt );
- if ( completion.len > iob_tailroom ( iobuf ) ) {
- DBGC ( hermon, "Hermon %p CQN %lx QPN %lx IDX %x "
- "overlength received packet length %zd\n",
- hermon, cq->cqn, qpn, wqe_idx, completion.len );
- return -EIO;
- }
+ if ( is_send ) {
+ /* Hand off to completion handler */
+ ib_complete_send ( ibdev, qp, iobuf, rc );
+ } else {
+ /* Set received length */
+ len = MLX_GET ( &cqe->normal, byte_cnt );
+ assert ( len <= iob_tailroom ( iobuf ) );
+ iob_put ( iobuf, len );
+ assert ( iob_len ( iobuf ) >= sizeof ( *grh ) );
+ grh = iobuf->data;
+ iob_pull ( iobuf, sizeof ( *grh ) );
+ /* Construct address vector */
+ memset ( &av, 0, sizeof ( av ) );
+ av.qpn = MLX_GET ( &cqe->normal, srq_rqpn );
+ av.lid = MLX_GET ( &cqe->normal, slid_smac47_32 );
+ av.sl = MLX_GET ( &cqe->normal, sl );
+ av.gid_present = MLX_GET ( &cqe->normal, g );
+ memcpy ( &av.gid, &grh->sgid, sizeof ( av.gid ) );
+ /* Hand off to completion handler */
+ ib_complete_recv ( ibdev, qp, &av, iobuf, rc );
}
- /* Pass off to caller's completion handler */
- complete = ( is_send ? complete_send : complete_recv );
- complete ( ibdev, qp, &completion, iobuf );
-
return rc;
}
@@ -1183,13 +1230,9 @@ static int hermon_complete ( struct ib_device *ibdev,
*
* @v ibdev Infiniband device
* @v cq Completion queue
- * @v complete_send Send completion handler
- * @v complete_recv Receive completion handler
*/
static void hermon_poll_cq ( struct ib_device *ibdev,
- struct ib_completion_queue *cq,
- ib_completer_t complete_send,
- ib_completer_t complete_recv ) {
+ struct ib_completion_queue *cq ) {
struct hermon *hermon = ib_get_drvdata ( ibdev );
struct hermon_completion_queue *hermon_cq = ib_cq_get_drvdata ( cq );
union hermonprm_completion_entry *cqe;
@@ -1209,8 +1252,7 @@ static void hermon_poll_cq ( struct ib_device *ibdev,
DBGCP_HD ( hermon, cqe, sizeof ( *cqe ) );
/* Handle completion */
- if ( ( rc = hermon_complete ( ibdev, cq, cqe, complete_send,
- complete_recv ) ) != 0 ) {
+ if ( ( rc = hermon_complete ( ibdev, cq, cqe ) ) != 0 ) {
DBGC ( hermon, "Hermon %p failed to complete: %s\n",
hermon, strerror ( rc ) );
DBGC_HD ( hermon, cqe, sizeof ( *cqe ) );
@@ -1380,6 +1422,9 @@ static void hermon_event_port_state_change ( struct hermon *hermon,
return;
}
+ /* Update MAD parameters */
+ ib_smc_update ( hermon->ibdev[port], hermon_mad );
+
/* Notify Infiniband core of link state change */
ib_link_state_changed ( hermon->ibdev[port] );
}
@@ -1468,6 +1513,9 @@ static int hermon_open ( struct ib_device *ibdev ) {
return rc;
}
+ /* Update MAD parameters */
+ ib_smc_update ( ibdev, hermon_mad );
+
return 0;
}
@@ -1582,51 +1630,6 @@ static void hermon_mcast_detach ( struct ib_device *ibdev,
}
}
-/***************************************************************************
- *
- * MAD operations
- *
- ***************************************************************************
- */
-
-/**
- * Issue management datagram
- *
- * @v ibdev Infiniband device
- * @v mad Management datagram
- * @v len Length of management datagram
- * @ret rc Return status code
- */
-static int hermon_mad ( struct ib_device *ibdev, struct ib_mad_hdr *mad,
- size_t len ) {
- struct hermon *hermon = ib_get_drvdata ( ibdev );
- union hermonprm_mad mad_ifc;
- int rc;
-
- /* Copy in request packet */
- memset ( &mad_ifc, 0, sizeof ( mad_ifc ) );
- assert ( len <= sizeof ( mad_ifc.mad ) );
- memcpy ( &mad_ifc.mad, mad, len );
-
- /* Issue MAD */
- if ( ( rc = hermon_cmd_mad_ifc ( hermon, ibdev->port,
- &mad_ifc ) ) != 0 ) {
- DBGC ( hermon, "Hermon %p could not issue MAD IFC: %s\n",
- hermon, strerror ( rc ) );
- return rc;
- }
-
- /* Copy out reply packet */
- memcpy ( mad, &mad_ifc.mad, len );
-
- if ( mad->status != 0 ) {
- DBGC ( hermon, "Hermon %p MAD IFC status %04x\n",
- hermon, ntohs ( mad->status ) );
- return -EIO;
- }
- return 0;
-}
-
/** Hermon Infiniband operations */
static struct ib_device_operations hermon_ib_operations = {
.create_cq = hermon_create_cq,
@@ -1642,7 +1645,6 @@ static struct ib_device_operations hermon_ib_operations = {
.close = hermon_close,
.mcast_attach = hermon_mcast_attach,
.mcast_detach = hermon_mcast_detach,
- .mad = hermon_mad,
};
/***************************************************************************
diff --git a/gpxe/src/drivers/infiniband/ib_packet.c b/gpxe/src/drivers/infiniband/ib_packet.c
new file mode 100644
index 00000000..74721337
--- /dev/null
+++ b/gpxe/src/drivers/infiniband/ib_packet.c
@@ -0,0 +1,234 @@
+/*
+ * Copyright (C) 2008 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 <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <byteswap.h>
+#include <gpxe/iobuf.h>
+#include <gpxe/infiniband.h>
+#include <gpxe/ib_packet.h>
+
+/**
+ * @file
+ *
+ * Infiniband Packet Formats
+ *
+ */
+
+/**
+ * Add IB headers
+ *
+ * @v ibdev Infiniband device
+ * @v iobuf I/O buffer to contain headers
+ * @v qp Queue pair
+ * @v payload_len Payload length
+ * @v av Address vector
+ */
+int ib_push ( struct ib_device *ibdev, struct io_buffer *iobuf,
+ struct ib_queue_pair *qp, size_t payload_len,
+ const struct ib_address_vector *av ) {
+ struct ib_local_route_header *lrh;
+ struct ib_global_route_header *grh;
+ struct ib_base_transport_header *bth;
+ struct ib_datagram_extended_transport_header *deth;
+ size_t orig_iob_len = iob_len ( iobuf );
+ size_t pad_len;
+ size_t lrh_len;
+ size_t grh_len;
+ unsigned int vl;
+ unsigned int lnh;
+
+ DBGC2 ( ibdev, "IBDEV %p TX %04x:%08lx => %04x:%08lx (key %08lx)\n",
+ ibdev, ibdev->lid, qp->qpn, av->lid, av->qpn, av->qkey );
+
+ /* Calculate packet length */
+ pad_len = ( (-payload_len) & 0x3 );
+ payload_len += pad_len;
+ payload_len += 4; /* ICRC */
+
+ /* Reserve space for headers */
+ orig_iob_len = iob_len ( iobuf );
+ deth = iob_push ( iobuf, sizeof ( *deth ) );
+ bth = iob_push ( iobuf, sizeof ( *bth ) );
+ grh_len = ( payload_len + iob_len ( iobuf ) - orig_iob_len );
+ grh = ( av->gid_present ?
+ iob_push ( iobuf, sizeof ( *grh ) ) : NULL );
+ lrh = iob_push ( iobuf, sizeof ( *lrh ) );
+ lrh_len = ( payload_len + iob_len ( iobuf ) - orig_iob_len );
+
+ /* Construct LRH */
+ vl = ( ( av->qpn == IB_QPN_SMP ) ? IB_VL_SMP : IB_VL_DEFAULT );
+ lrh->vl__lver = ( vl << 4 );
+ lnh = ( grh ? IB_LNH_GRH : IB_LNH_BTH );
+ lrh->sl__lnh = ( ( av->sl << 4 ) | lnh );
+ lrh->dlid = htons ( av->lid );
+ lrh->length = htons ( lrh_len >> 2 );
+ lrh->slid = htons ( ibdev->lid );
+
+ /* Construct GRH, if required */
+ if ( grh ) {
+ grh->ipver__tclass__flowlabel =
+ htonl ( IB_GRH_IPVER_IPv6 << 28 );
+ grh->paylen = htons ( grh_len );
+ grh->nxthdr = IB_GRH_NXTHDR_IBA;
+ grh->hoplmt = 0;
+ memcpy ( &grh->sgid, &ibdev->gid, sizeof ( grh->sgid ) );
+ memcpy ( &grh->dgid, &av->gid, sizeof ( grh->dgid ) );
+ }
+
+ /* Construct BTH */
+ bth->opcode = BTH_OPCODE_UD_SEND;
+ bth->se__m__padcnt__tver = ( pad_len << 4 );
+ bth->pkey = htons ( ibdev->pkey );
+ bth->dest_qp = htonl ( av->qpn );
+ bth->ack__psn = htonl ( ( ibdev->psn++ ) & 0xffffffUL );
+
+ /* Construct DETH */
+ deth->qkey = htonl ( av->qkey );
+ deth->src_qp = htonl ( qp->qpn );
+
+ DBGCP_HDA ( ibdev, 0, iobuf->data,
+ ( iob_len ( iobuf ) - orig_iob_len ) );
+
+ return 0;
+}
+
+/**
+ * Remove IB headers
+ *
+ * @v ibdev Infiniband device
+ * @v iobuf I/O buffer containing headers
+ * @v qp Queue pair to fill in, or NULL
+ * @v payload_len Payload length to fill in, or NULL
+ * @v av Address vector to fill in
+ */
+int ib_pull ( struct ib_device *ibdev, struct io_buffer *iobuf,
+ struct ib_queue_pair **qp, size_t *payload_len,
+ struct ib_address_vector *av ) {
+ struct ib_local_route_header *lrh;
+ struct ib_global_route_header *grh;
+ struct ib_base_transport_header *bth;
+ struct ib_datagram_extended_transport_header *deth;
+ size_t orig_iob_len = iob_len ( iobuf );
+ unsigned int lnh;
+ size_t pad_len;
+ unsigned long qpn;
+ unsigned int lid;
+
+ /* Clear return values */
+ if ( qp )
+ *qp = NULL;
+ if ( payload_len )
+ *payload_len = 0;
+ memset ( av, 0, sizeof ( *av ) );
+
+ /* Extract LRH */
+ if ( iob_len ( iobuf ) < sizeof ( *lrh ) ) {
+ DBGC ( ibdev, "IBDEV %p RX too short (%zd bytes) for LRH\n",
+ ibdev, iob_len ( iobuf ) );
+ return -EINVAL;
+ }
+ lrh = iobuf->data;
+ iob_pull ( iobuf, sizeof ( *lrh ) );
+ av->lid = ntohs ( lrh->slid );
+ av->sl = ( lrh->sl__lnh >> 4 );
+ lnh = ( lrh->sl__lnh & 0x3 );
+ lid = ntohs ( lrh->dlid );
+
+ /* Reject unsupported packets */
+ if ( ! ( ( lnh == IB_LNH_BTH ) || ( lnh == IB_LNH_GRH ) ) ) {
+ DBGC ( ibdev, "IBDEV %p RX unsupported LNH %x\n",
+ ibdev, lnh );
+ return -ENOTSUP;
+ }
+
+ /* Extract GRH, if present */
+ if ( lnh == IB_LNH_GRH ) {
+ if ( iob_len ( iobuf ) < sizeof ( *grh ) ) {
+ DBGC ( ibdev, "IBDEV %p RX too short (%zd bytes) "
+ "for GRH\n", ibdev, iob_len ( iobuf ) );
+ return -EINVAL;
+ }
+ grh = iobuf->data;
+ iob_pull ( iobuf, sizeof ( *grh ) );
+ av->gid_present = 1;
+ memcpy ( &av->gid, &grh->sgid, sizeof ( av->gid ) );
+ } else {
+ grh = NULL;
+ }
+
+ /* Extract BTH */
+ if ( iob_len ( iobuf ) < sizeof ( *bth ) ) {
+ DBGC ( ibdev, "IBDEV %p RX too short (%zd bytes) for BTH\n",
+ ibdev, iob_len ( iobuf ) );
+ return -EINVAL;
+ }
+ bth = iobuf->data;
+ iob_pull ( iobuf, sizeof ( *bth ) );
+ if ( bth->opcode != BTH_OPCODE_UD_SEND ) {
+ DBGC ( ibdev, "IBDEV %p unsupported BTH opcode %x\n",
+ ibdev, bth->opcode );
+ return -ENOTSUP;
+ }
+ qpn = ntohl ( bth->dest_qp );
+
+ /* Extract DETH */
+ if ( iob_len ( iobuf ) < sizeof ( *deth ) ) {
+ DBGC ( ibdev, "IBDEV %p RX too short (%zd bytes) for DETH\n",
+ ibdev, iob_len ( iobuf ) );
+ return -EINVAL;
+ }
+ deth = iobuf->data;
+ iob_pull ( iobuf, sizeof ( *deth ) );
+ av->qpn = ntohl ( deth->src_qp );
+ av->qkey = ntohl ( deth->qkey );
+
+ /* Calculate payload length, if applicable */
+ if ( payload_len ) {
+ pad_len = ( ( bth->se__m__padcnt__tver >> 4 ) & 0x3 );
+ *payload_len = ( ( ntohs ( lrh->length ) << 2 )
+ - ( orig_iob_len - iob_len ( iobuf ) )
+ - pad_len - 4 /* ICRC */ );
+ }
+
+ /* Determine destination QP, if applicable */
+ if ( qp ) {
+ if ( IB_LID_MULTICAST ( lid ) && grh ) {
+ *qp = ib_find_qp_mgid ( ibdev, &grh->dgid );
+ } else {
+ *qp = ib_find_qp_qpn ( ibdev, qpn );
+ }
+ if ( ! *qp ) {
+ DBGC ( ibdev, "IBDEV %p RX for nonexistent QP\n",
+ ibdev );
+ return -ENODEV;
+ }
+ }
+
+ DBGC2 ( ibdev, "IBDEV %p RX %04x:%08lx <= %04x:%08lx (key %08lx)\n",
+ ibdev, lid,
+ ( IB_LID_MULTICAST( lid ) ? ( qp ? (*qp)->qpn : -1UL ) : qpn ),
+ av->lid, av->qpn, ntohl ( deth->qkey ) );
+ DBGCP_HDA ( ibdev, 0,
+ ( iobuf->data - ( orig_iob_len - iob_len ( iobuf ) ) ),
+ ( orig_iob_len - iob_len ( iobuf ) ) );
+
+ return 0;
+}
diff --git a/gpxe/src/drivers/infiniband/ib_sma.c b/gpxe/src/drivers/infiniband/ib_sma.c
new file mode 100644
index 00000000..9426c8f1
--- /dev/null
+++ b/gpxe/src/drivers/infiniband/ib_sma.c
@@ -0,0 +1,553 @@
+/*
+ * Copyright (C) 2008 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 <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <byteswap.h>
+#include <gpxe/infiniband.h>
+#include <gpxe/iobuf.h>
+#include <gpxe/process.h>
+#include <gpxe/ib_sma.h>
+
+/**
+ * @file
+ *
+ * Infiniband Subnet Management Agent
+ *
+ */
+
+/**
+ * Get node information
+ *
+ * @v sma Subnet management agent
+ * @v get Attribute to get
+ */
+static void ib_sma_get_node_info ( struct ib_sma *sma,
+ union ib_smp_data *get ) {
+ struct ib_device *ibdev = sma->ibdev;
+ struct ib_node_info *node_info = &get->node_info;
+ struct ib_device *tmp;
+
+ memset ( node_info, 0, sizeof ( *node_info ) );
+ node_info->base_version = IB_MGMT_BASE_VERSION;
+ node_info->class_version = IB_SMP_CLASS_VERSION;
+ node_info->node_type = IB_NODE_TYPE_HCA;
+ /* Search for IB devices with the same physical device to
+ * identify port count and a suitable Node GUID.
+ */
+ for_each_ibdev ( tmp ) {
+ if ( tmp->dev != ibdev->dev )
+ continue;
+ if ( node_info->num_ports == 0 ) {
+ memcpy ( node_info->sys_guid, &tmp->gid.u.half[1],
+ sizeof ( node_info->sys_guid ) );
+ memcpy ( node_info->node_guid, &tmp->gid.u.half[1],
+ sizeof ( node_info->node_guid ) );
+ }
+ node_info->num_ports++;
+ }
+ memcpy ( node_info->port_guid, &ibdev->gid.u.half[1],
+ sizeof ( node_info->port_guid ) );
+ node_info->partition_cap = htons ( 1 );
+ node_info->local_port_num = ibdev->port;
+}
+
+/**
+ * Get node description
+ *
+ * @v sma Subnet management agent
+ * @v get Attribute to get
+ */
+static void ib_sma_get_node_desc ( struct ib_sma *sma,
+ union ib_smp_data *get ) {
+ struct ib_device *ibdev = sma->ibdev;
+ struct ib_node_desc *node_desc = &get->node_desc;
+ struct ib_gid_half *guid = &ibdev->gid.u.half[1];
+
+ memset ( node_desc, 0, sizeof ( *node_desc ) );
+ snprintf ( node_desc->node_string, sizeof ( node_desc->node_string ),
+ "gPXE %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x (%s)",
+ guid->bytes[0], guid->bytes[1], guid->bytes[2],
+ guid->bytes[3], guid->bytes[4], guid->bytes[5],
+ guid->bytes[6], guid->bytes[7], ibdev->dev->name );
+}
+
+/**
+ * Get GUID information
+ *
+ * @v sma Subnet management agent
+ * @v get Attribute to get
+ */
+static void ib_sma_get_guid_info ( struct ib_sma *sma,
+ union ib_smp_data *get ) {
+ struct ib_device *ibdev = sma->ibdev;
+ struct ib_guid_info *guid_info = &get->guid_info;
+
+ memset ( guid_info, 0, sizeof ( *guid_info ) );
+ memcpy ( guid_info->guid[0], &ibdev->gid.u.half[1],
+ sizeof ( guid_info->guid[0] ) );
+}
+
+/**
+ * Get port information
+ *
+ * @v sma Subnet management agent
+ * @v get Attribute to get
+ */
+static void ib_sma_get_port_info ( struct ib_sma *sma,
+ union ib_smp_data *get ) {
+ struct ib_device *ibdev = sma->ibdev;
+ struct ib_port_info *port_info = &get->port_info;
+
+ memset ( port_info, 0, sizeof ( *port_info ) );
+ memcpy ( port_info->gid_prefix, &ibdev->gid.u.half[0],
+ sizeof ( port_info->gid_prefix ) );
+ port_info->lid = ntohs ( ibdev->lid );
+ port_info->mastersm_lid = ntohs ( ibdev->sm_lid );
+ port_info->local_port_num = ibdev->port;
+ port_info->link_width_enabled = ibdev->link_width;
+ port_info->link_width_supported = ibdev->link_width;
+ port_info->link_width_active = ibdev->link_width;
+ port_info->link_speed_supported__port_state =
+ ( ( ibdev->link_speed << 4 ) | ibdev->port_state );
+ port_info->port_phys_state__link_down_def_state =
+ ( ( IB_PORT_PHYS_STATE_POLLING << 4 ) |
+ IB_PORT_PHYS_STATE_POLLING );
+ port_info->link_speed_active__link_speed_enabled =
+ ( ( ibdev->link_speed << 4 ) | ibdev->link_speed );
+ port_info->neighbour_mtu__mastersm_sl =
+ ( ( IB_MTU_2048 << 4 ) | ibdev->sm_sl );
+ port_info->vl_cap__init_type = ( IB_VL_0 << 4 );
+ port_info->init_type_reply__mtu_cap = IB_MTU_2048;
+ port_info->operational_vls__enforcement = ( IB_VL_0 << 4 );
+ port_info->guid_cap = 1;
+}
+
+/**
+ * Set port information
+ *
+ * @v sma Subnet management agent
+ * @v set Attribute to set
+ * @ret rc Return status code
+ */
+static int ib_sma_set_port_info ( struct ib_sma *sma,
+ const union ib_smp_data *set ) {
+ struct ib_device *ibdev = sma->ibdev;
+ const struct ib_port_info *port_info = &set->port_info;
+
+ memcpy ( &ibdev->gid.u.half[0], port_info->gid_prefix,
+ sizeof ( ibdev->gid.u.half[0] ) );
+ ibdev->lid = ntohs ( port_info->lid );
+ ibdev->sm_lid = ntohs ( port_info->mastersm_lid );
+ ibdev->sm_sl = ( port_info->neighbour_mtu__mastersm_sl & 0xf );
+
+ if ( ! sma->op->set_port_info ) {
+ /* Not an error; we just ignore all other settings */
+ return 0;
+ }
+
+ return sma->op->set_port_info ( ibdev, port_info );
+}
+
+/**
+ * Get partition key table
+ *
+ * @v sma Subnet management agent
+ * @v get Attribute to get
+ */
+static void ib_sma_get_pkey_table ( struct ib_sma *sma,
+ union ib_smp_data *get ) {
+ struct ib_device *ibdev = sma->ibdev;
+ struct ib_pkey_table *pkey_table = &get->pkey_table;
+
+ memset ( pkey_table, 0, sizeof ( *pkey_table ) );
+ pkey_table->pkey[0] = htons ( ibdev->pkey );
+}
+
+/**
+ * Set partition key table
+ *
+ * @v sma Subnet management agent
+ * @v set Attribute to set
+ */
+static int ib_sma_set_pkey_table ( struct ib_sma *sma,
+ const union ib_smp_data *get ) {
+ struct ib_device *ibdev = sma->ibdev;
+ const struct ib_pkey_table *pkey_table = &get->pkey_table;
+
+ ibdev->pkey = ntohs ( pkey_table->pkey[0] );
+ return 0;
+}
+
+/** An attribute handler */
+struct ib_sma_handler {
+ /** Attribute (in network byte order) */
+ uint16_t attr_id;
+ /** Get attribute
+ *
+ * @v sma Subnet management agent
+ * @v get Attribute to get
+ * @ret rc Return status code
+ */
+ void ( * get ) ( struct ib_sma *sma, union ib_smp_data *get );
+ /** Set attribute
+ *
+ * @v sma Subnet management agent
+ * @v set Attribute to set
+ * @ret rc Return status code
+ */
+ int ( * set ) ( struct ib_sma *sma, const union ib_smp_data *set );
+};
+
+/** List of attribute handlers */
+static struct ib_sma_handler ib_sma_handlers[] = {
+ { htons ( IB_SMP_ATTR_NODE_DESC ),
+ ib_sma_get_node_desc, NULL },
+ { htons ( IB_SMP_ATTR_NODE_INFO ),
+ ib_sma_get_node_info, NULL },
+ { htons ( IB_SMP_ATTR_GUID_INFO ),
+ ib_sma_get_guid_info, NULL },
+ { htons ( IB_SMP_ATTR_PORT_INFO ),
+ ib_sma_get_port_info, ib_sma_set_port_info },
+ { htons ( IB_SMP_ATTR_PKEY_TABLE ),
+ ib_sma_get_pkey_table, ib_sma_set_pkey_table },
+};
+
+/**
+ * Identify attribute handler
+ *
+ * @v attr_id Attribute ID (in network byte order)
+ * @ret handler Attribute handler (or NULL)
+ */
+static struct ib_sma_handler * ib_sma_handler ( uint16_t attr_id ) {
+ struct ib_sma_handler *handler;
+ unsigned int i;
+
+ for ( i = 0 ; i < ( sizeof ( ib_sma_handlers ) /
+ sizeof ( ib_sma_handlers[0] ) ) ; i++ ) {
+ handler = &ib_sma_handlers[i];
+ if ( handler->attr_id == attr_id )
+ return handler;
+ }
+
+ return NULL;
+}
+
+/**
+ * Respond to management datagram
+ *
+ * @v sma Subnet management agent
+ * @v mad Management datagram
+ * @ret rc Return status code
+ */
+static int ib_sma_mad ( struct ib_sma *sma, union ib_mad *mad ) {
+ struct ib_device *ibdev = sma->ibdev;
+ struct ib_mad_hdr *hdr = &mad->hdr;
+ struct ib_mad_smp *smp = &mad->smp;
+ struct ib_sma_handler *handler = NULL;
+ unsigned int hop_pointer;
+ unsigned int hop_count;
+ int rc;
+
+ DBGC ( sma, "SMA %p received SMP with bv=%02x mc=%02x cv=%02x "
+ "meth=%02x attr=%04x mod=%08lx\n", sma, hdr->base_version,
+ hdr->mgmt_class, hdr->class_version, hdr->method,
+ ntohs ( hdr->attr_id ), ntohl ( hdr->attr_mod ) );
+ DBGC2_HDA ( sma, 0, mad, sizeof ( *mad ) );
+
+ /* Sanity checks */
+ if ( hdr->base_version != IB_MGMT_BASE_VERSION ) {
+ DBGC ( sma, "SMA %p unsupported base version %x\n",
+ sma, hdr->base_version );
+ return -ENOTSUP;
+ }
+ if ( ( hdr->mgmt_class != IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE ) &&
+ ( hdr->mgmt_class != IB_MGMT_CLASS_SUBN_LID_ROUTED ) ) {
+ DBGC ( sma, "SMA %p unsupported management class %x\n",
+ sma, hdr->mgmt_class );
+ return -ENOTSUP;
+ }
+ if ( hdr->class_version != IB_SMP_CLASS_VERSION ) {
+ DBGC ( sma, "SMA %p unsupported class version %x\n",
+ sma, hdr->class_version );
+ return -ENOTSUP;
+ }
+ if ( ( hdr->method != IB_MGMT_METHOD_GET ) &&
+ ( hdr->method != IB_MGMT_METHOD_SET ) ) {
+ DBGC ( sma, "SMA %p unsupported method %x\n",
+ sma, hdr->method );
+ return -ENOTSUP;
+ }
+
+ /* Identify handler */
+ if ( ! ( handler = ib_sma_handler ( hdr->attr_id ) ) ) {
+ DBGC ( sma, "SMA %p unsupported attribute %x\n",
+ sma, ntohs ( hdr->attr_id ) );
+ hdr->status = htons ( IB_MGMT_STATUS_UNSUPPORTED_METHOD_ATTR );
+ goto respond_without_data;
+ }
+
+ /* Set attribute (if applicable) */
+ if ( hdr->method != IB_MGMT_METHOD_SET ) {
+ hdr->status = htons ( IB_MGMT_STATUS_OK );
+ goto respond;
+ }
+ if ( ! handler->set ) {
+ DBGC ( sma, "SMA %p attribute %x is unsettable\n",
+ sma, ntohs ( hdr->attr_id ) );
+ hdr->status = htons ( IB_MGMT_STATUS_UNSUPPORTED_METHOD_ATTR );
+ goto respond;
+ }
+ if ( ( rc = handler->set ( sma, &smp->smp_data ) ) != 0 ) {
+ DBGC ( sma, "SMA %p could not set attribute %x: %s\n",
+ sma, ntohs ( hdr->attr_id ), strerror ( rc ) );
+ hdr->status = htons ( IB_MGMT_STATUS_UNSUPPORTED_METHOD_ATTR );
+ goto respond;
+ }
+
+ hdr->status = htons ( IB_MGMT_STATUS_OK );
+
+ respond:
+ /* Get attribute */
+ handler->get ( sma, &smp->smp_data );
+
+ respond_without_data:
+
+ /* Set method to "Get Response" */
+ hdr->method = IB_MGMT_METHOD_GET_RESP;
+
+ /* Set response fields for directed route SMPs */
+ if ( hdr->mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE ) {
+ hdr->status |= htons ( IB_SMP_STATUS_D_INBOUND );
+ hop_pointer = smp->mad_hdr.class_specific.smp.hop_pointer;
+ hop_count = smp->mad_hdr.class_specific.smp.hop_count;
+ assert ( hop_count == hop_pointer );
+ if ( hop_pointer < ( sizeof ( smp->return_path.hops ) /
+ sizeof ( smp->return_path.hops[0] ) ) ) {
+ smp->return_path.hops[hop_pointer] = ibdev->port;
+ } else {
+ DBGC ( sma, "SMA %p invalid hop pointer %d\n",
+ sma, hop_pointer );
+ return -EINVAL;
+ }
+ }
+
+ DBGC ( sma, "SMA %p responding with status=%04x\n",
+ sma, ntohs ( hdr->status ) );
+ DBGC2_HDA ( sma, 0, mad, sizeof ( *mad ) );
+
+ return 0;
+}
+
+/**
+ * Refill SMA receive ring
+ *
+ * @v sma Subnet management agent
+ */
+static void ib_sma_refill_recv ( struct ib_sma *sma ) {
+ struct ib_device *ibdev = sma->ibdev;
+ struct io_buffer *iobuf;
+ int rc;
+
+ while ( sma->qp->recv.fill < IB_SMA_NUM_RECV_WQES ) {
+
+ /* Allocate I/O buffer */
+ iobuf = alloc_iob ( IB_SMA_PAYLOAD_LEN );
+ if ( ! iobuf ) {
+ /* Non-fatal; we will refill on next attempt */
+ return;
+ }
+
+ /* Post I/O buffer */
+ if ( ( rc = ib_post_recv ( ibdev, sma->qp, iobuf ) ) != 0 ) {
+ DBGC ( sma, "SMA %p could not refill: %s\n",
+ sma, strerror ( rc ) );
+ free_iob ( iobuf );
+ /* Give up */
+ return;
+ }
+ }
+}
+
+/**
+ * Complete SMA send
+ *
+ *
+ * @v ibdev Infiniband device
+ * @v qp Queue pair
+ * @v iobuf I/O buffer
+ * @v rc Completion status code
+ */
+static void ib_sma_complete_send ( struct ib_device *ibdev __unused,
+ struct ib_queue_pair *qp,
+ struct io_buffer *iobuf, int rc ) {
+ struct ib_sma *sma = ib_qp_get_ownerdata ( qp );
+
+ if ( rc != 0 ) {
+ DBGC ( sma, "SMA %p send completion error: %s\n",
+ sma, strerror ( rc ) );
+ }
+ free_iob ( iobuf );
+}
+
+/**
+ * Complete SMA receive
+ *
+ *
+ * @v ibdev Infiniband device
+ * @v qp Queue pair
+ * @v av Address vector
+ * @v iobuf I/O buffer
+ * @v rc Completion status code
+ */
+static void ib_sma_complete_recv ( struct ib_device *ibdev,
+ struct ib_queue_pair *qp,
+ struct ib_address_vector *av,
+ struct io_buffer *iobuf, int rc ) {
+ struct ib_sma *sma = ib_qp_get_ownerdata ( qp );
+ union ib_mad *mad;
+
+ /* Ignore errors */
+ if ( rc != 0 ) {
+ DBGC ( sma, "SMA %p RX error: %s\n", sma, strerror ( rc ) );
+ goto err;
+ }
+
+ /* Sanity check */
+ if ( iob_len ( iobuf ) != sizeof ( *mad ) ) {
+ DBGC ( sma, "SMA %p RX bad size (%zd bytes)\n",
+ sma, iob_len ( iobuf ) );
+ goto err;
+ }
+ mad = iobuf->data;
+
+ /* Construct MAD response */
+ if ( ( rc = ib_sma_mad ( sma, mad ) ) != 0 ) {
+ DBGC ( sma, "SMA %p could not construct MAD response: %s\n",
+ sma, strerror ( rc ) );
+ goto err;
+ }
+
+ /* Send MAD response */
+ if ( ( rc = ib_post_send ( ibdev, qp, av, iobuf ) ) != 0 ) {
+ DBGC ( sma, "SMA %p could not send MAD response: %s\n",
+ sma, strerror ( rc ) );
+ goto err;
+ }
+
+ return;
+
+ err:
+ free_iob ( iobuf );
+}
+
+/** SMA completion operations */
+static struct ib_completion_queue_operations ib_sma_completion_ops = {
+ .complete_send = ib_sma_complete_send,
+ .complete_recv = ib_sma_complete_recv,
+};
+
+/**
+ * Poll SMA
+ *
+ * @v process Process
+ */
+static void ib_sma_step ( struct process *process ) {
+ struct ib_sma *sma =
+ container_of ( process, struct ib_sma, poll );
+ struct ib_device *ibdev = sma->ibdev;
+
+ /* Poll the kernel completion queue */
+ ib_poll_cq ( ibdev, sma->cq );
+
+ /* Refill the receive ring */
+ ib_sma_refill_recv ( sma );
+}
+
+/**
+ * Create SMA
+ *
+ * @v sma Subnet management agent
+ * @v ibdev Infiniband device
+ * @v op Subnet management operations
+ * @ret rc Return status code
+ */
+int ib_create_sma ( struct ib_sma *sma, struct ib_device *ibdev,
+ struct ib_sma_operations *op ) {
+ int rc;
+
+ /* Initialise fields */
+ memset ( sma, 0, sizeof ( *sma ) );
+ sma->ibdev = ibdev;
+ sma->op = op;
+ process_init ( &sma->poll, ib_sma_step, &ibdev->refcnt );
+
+ /* Create completion queue */
+ sma->cq = ib_create_cq ( ibdev, IB_SMA_NUM_CQES,
+ &ib_sma_completion_ops );
+ if ( ! sma->cq ) {
+ rc = -ENOMEM;
+ goto err_create_cq;
+ }
+
+ /* Create queue pair */
+ sma->qp = ib_create_qp ( ibdev, IB_SMA_NUM_SEND_WQES, sma->cq,
+ IB_SMA_NUM_RECV_WQES, sma->cq, 0 );
+ if ( ! sma->qp ) {
+ rc = -ENOMEM;
+ goto err_create_qp;
+ }
+ ib_qp_set_ownerdata ( sma->qp, sma );
+
+ /* If we don't get QP0, we can't function */
+ if ( sma->qp->qpn != IB_QPN_SMP ) {
+ DBGC ( sma, "SMA %p on QPN %lx, needs to be on QPN 0\n",
+ sma, sma->qp->qpn );
+ rc = -ENOTSUP;
+ goto err_not_qp0;
+ }
+
+ /* Fill receive ring */
+ ib_sma_refill_recv ( sma );
+ return 0;
+
+ err_not_qp0:
+ ib_destroy_qp ( ibdev, sma->qp );
+ err_create_qp:
+ ib_destroy_cq ( ibdev, sma->cq );
+ err_create_cq:
+ process_del ( &sma->poll );
+ return rc;
+}
+
+/**
+ * Destroy SMA
+ *
+ * @v sma Subnet management agent
+ */
+void ib_destroy_sma ( struct ib_sma *sma ) {
+ struct ib_device *ibdev = sma->ibdev;
+
+ ib_destroy_qp ( ibdev, sma->qp );
+ ib_destroy_cq ( ibdev, sma->cq );
+ process_del ( &sma->poll );
+}
diff --git a/gpxe/src/drivers/infiniband/ib_smc.c b/gpxe/src/drivers/infiniband/ib_smc.c
new file mode 100644
index 00000000..c07a4fef
--- /dev/null
+++ b/gpxe/src/drivers/infiniband/ib_smc.c
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2008 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 <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <byteswap.h>
+#include <gpxe/infiniband.h>
+#include <gpxe/ib_smc.h>
+
+/**
+ * @file
+ *
+ * Infiniband Subnet Management Client
+ *
+ */
+
+/**
+ * Get port information
+ *
+ * @v ibdev Infiniband device
+ * @v local_mad Method for issuing local MADs
+ * @v mad Management datagram to fill in
+ * @ret rc Return status code
+ */
+static int ib_smc_get_port_info ( struct ib_device *ibdev,
+ ib_local_mad_t local_mad,
+ union ib_mad *mad ) {
+ int rc;
+
+ /* Construct MAD */
+ memset ( mad, 0, sizeof ( *mad ) );
+ mad->hdr.base_version = IB_MGMT_BASE_VERSION;
+ mad->hdr.mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED;
+ mad->hdr.class_version = 1;
+ mad->hdr.method = IB_MGMT_METHOD_GET;
+ mad->hdr.attr_id = htons ( IB_SMP_ATTR_PORT_INFO );
+ mad->hdr.attr_mod = htonl ( ibdev->port );
+
+ if ( ( rc = local_mad ( ibdev, mad ) ) != 0 ) {
+ DBGC ( ibdev, "IBDEV %p could not get port info: %s\n",
+ ibdev, strerror ( rc ) );
+ return rc;
+ }
+ return 0;
+}
+
+/**
+ * Get GUID information
+ *
+ * @v ibdev Infiniband device
+ * @v local_mad Method for issuing local MADs
+ * @v mad Management datagram to fill in
+ * @ret rc Return status code
+ */
+static int ib_smc_get_guid_info ( struct ib_device *ibdev,
+ ib_local_mad_t local_mad,
+ union ib_mad *mad ) {
+ int rc;
+
+ /* Construct MAD */
+ memset ( mad, 0, sizeof ( *mad ) );
+ mad->hdr.base_version = IB_MGMT_BASE_VERSION;
+ mad->hdr.mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED;
+ mad->hdr.class_version = 1;
+ mad->hdr.method = IB_MGMT_METHOD_GET;
+ mad->hdr.attr_id = htons ( IB_SMP_ATTR_GUID_INFO );
+
+ if ( ( rc = local_mad ( ibdev, mad ) ) != 0 ) {
+ DBGC ( ibdev, "IBDEV %p could not get GUID info: %s\n",
+ ibdev, strerror ( rc ) );
+ return rc;
+ }
+ return 0;
+}
+
+/**
+ * Get partition key table
+ *
+ * @v ibdev Infiniband device
+ * @v local_mad Method for issuing local MADs
+ * @v mad Management datagram to fill in
+ * @ret rc Return status code
+ */
+static int ib_smc_get_pkey_table ( struct ib_device *ibdev,
+ ib_local_mad_t local_mad,
+ union ib_mad *mad ) {
+ int rc;
+
+ /* Construct MAD */
+ memset ( mad, 0, sizeof ( *mad ) );
+ mad->hdr.base_version = IB_MGMT_BASE_VERSION;
+ mad->hdr.mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED;
+ mad->hdr.class_version = 1;
+ mad->hdr.method = IB_MGMT_METHOD_GET;
+ mad->hdr.attr_id = htons ( IB_SMP_ATTR_PKEY_TABLE );
+
+ if ( ( rc = local_mad ( ibdev, mad ) ) != 0 ) {
+ DBGC ( ibdev, "IBDEV %p could not get pkey table: %s\n",
+ ibdev, strerror ( rc ) );
+ return rc;
+ }
+ return 0;
+}
+
+/**
+ * Get MAD parameters
+ *
+ * @v ibdev Infiniband device
+ * @v local_mad Method for issuing local MADs
+ * @ret rc Return status code
+ */
+int ib_smc_update ( struct ib_device *ibdev, ib_local_mad_t local_mad ) {
+ union ib_mad mad;
+ union ib_smp_data *smp = &mad.smp.smp_data;
+ int rc;
+
+ /* Port info gives us the link state, the first half of the
+ * port GID and the SM LID.
+ */
+ if ( ( rc = ib_smc_get_port_info ( ibdev, local_mad, &mad ) ) != 0 )
+ return rc;
+ ibdev->port_state =
+ ( smp->port_info.link_speed_supported__port_state & 0x0f );
+ memcpy ( &ibdev->gid.u.half[0], smp->port_info.gid_prefix,
+ sizeof ( ibdev->gid.u.half[0] ) );
+ ibdev->lid = ntohs ( smp->port_info.lid );
+ ibdev->sm_lid = ntohs ( smp->port_info.mastersm_lid );
+ ibdev->sm_sl = ( smp->port_info.neighbour_mtu__mastersm_sl & 0xf );
+
+ /* GUID info gives us the second half of the port GID */
+ if ( ( rc = ib_smc_get_guid_info ( ibdev, local_mad, &mad ) ) != 0 )
+ return rc;
+ memcpy ( &ibdev->gid.u.half[1], smp->guid_info.guid[0],
+ sizeof ( ibdev->gid.u.half[1] ) );
+
+ /* Get partition key */
+ if ( ( rc = ib_smc_get_pkey_table ( ibdev, local_mad, &mad ) ) != 0 )
+ return rc;
+ ibdev->pkey = ntohs ( smp->pkey_table.pkey[0] );
+
+ DBGC ( ibdev, "IBDEV %p port GID is %08lx:%08lx:%08lx:%08lx\n", ibdev,
+ htonl ( ibdev->gid.u.dwords[0] ),
+ htonl ( ibdev->gid.u.dwords[1] ),
+ htonl ( ibdev->gid.u.dwords[2] ),
+ htonl ( ibdev->gid.u.dwords[3] ) );
+
+ return 0;
+}
diff --git a/gpxe/src/drivers/infiniband/linda.c b/gpxe/src/drivers/infiniband/linda.c
new file mode 100644
index 00000000..170eec47
--- /dev/null
+++ b/gpxe/src/drivers/infiniband/linda.c
@@ -0,0 +1,2396 @@
+/*
+ * Copyright (C) 2008 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 <stdint.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <assert.h>
+#include <gpxe/pci.h>
+#include <gpxe/infiniband.h>
+#include <gpxe/i2c.h>
+#include <gpxe/bitbash.h>
+#include <gpxe/malloc.h>
+#include <gpxe/iobuf.h>
+#include <gpxe/ib_sma.h>
+#include "linda.h"
+
+/**
+ * @file
+ *
+ * QLogic Linda Infiniband HCA
+ *
+ */
+
+/** A Linda send work queue */
+struct linda_send_work_queue {
+ /** Send buffer usage */
+ uint8_t *send_buf;
+ /** Producer index */
+ unsigned int prod;
+ /** Consumer index */
+ unsigned int cons;
+};
+
+/** A Linda receive work queue */
+struct linda_recv_work_queue {
+ /** Receive header ring */
+ void *header;
+ /** Receive header producer offset (written by hardware) */
+ struct QIB_7220_scalar header_prod;
+ /** Receive header consumer offset */
+ unsigned int header_cons;
+ /** Offset within register space of the eager array */
+ unsigned long eager_array;
+ /** Number of entries in eager array */
+ unsigned int eager_entries;
+ /** Eager array producer index */
+ unsigned int eager_prod;
+ /** Eager array consumer index */
+ unsigned int eager_cons;
+};
+
+/** A Linda HCA */
+struct linda {
+ /** Registers */
+ void *regs;
+
+ /** In-use contexts */
+ uint8_t used_ctx[LINDA_NUM_CONTEXTS];
+ /** Send work queues */
+ struct linda_send_work_queue send_wq[LINDA_NUM_CONTEXTS];
+ /** Receive work queues */
+ struct linda_recv_work_queue recv_wq[LINDA_NUM_CONTEXTS];
+
+ /** Offset within register space of the first send buffer */
+ unsigned long send_buffer_base;
+ /** Send buffer availability (reported by hardware) */
+ struct QIB_7220_SendBufAvail *sendbufavail;
+ /** Send buffer availability (maintained by software) */
+ uint8_t send_buf[LINDA_MAX_SEND_BUFS];
+ /** Send buffer availability producer counter */
+ unsigned int send_buf_prod;
+ /** Send buffer availability consumer counter */
+ unsigned int send_buf_cons;
+ /** Number of reserved send buffers (across all QPs) */
+ unsigned int reserved_send_bufs;
+
+ /** I2C bit-bashing interface */
+ struct i2c_bit_basher i2c;
+ /** I2C serial EEPROM */
+ struct i2c_device eeprom;
+
+ /** Subnet management agent */
+ struct ib_sma sma;
+};
+
+/***************************************************************************
+ *
+ * Linda register access
+ *
+ ***************************************************************************
+ *
+ * This card requires atomic 64-bit accesses. Strange things happen
+ * if you try to use 32-bit accesses; sometimes they work, sometimes
+ * they don't, sometimes you get random data.
+ *
+ * These accessors use the "movq" MMX instruction, and so won't work
+ * on really old Pentiums (which won't have PCIe anyway, so this is
+ * something of a moot point).
+ */
+
+/**
+ * Read Linda qword register
+ *
+ * @v linda Linda device
+ * @v dwords Register buffer to read into
+ * @v offset Register offset
+ */
+static void linda_readq ( struct linda *linda, uint32_t *dwords,
+ unsigned long offset ) {
+ void *addr = ( linda->regs + offset );
+
+ __asm__ __volatile__ ( "movq (%1), %%mm0\n\t"
+ "movq %%mm0, (%0)\n\t"
+ : : "r" ( dwords ), "r" ( addr ) : "memory" );
+
+ DBGIO ( "[%08lx] => %08lx%08lx\n",
+ virt_to_phys ( addr ), dwords[1], dwords[0] );
+}
+#define linda_readq( _linda, _ptr, _offset ) \
+ linda_readq ( (_linda), (_ptr)->u.dwords, (_offset) )
+#define linda_readq_array8b( _linda, _ptr, _offset, _idx ) \
+ linda_readq ( (_linda), (_ptr), ( (_offset) + ( (_idx) * 8 ) ) )
+#define linda_readq_array64k( _linda, _ptr, _offset, _idx ) \
+ linda_readq ( (_linda), (_ptr), ( (_offset) + ( (_idx) * 65536 ) ) )
+
+/**
+ * Write Linda qword register
+ *
+ * @v linda Linda device
+ * @v dwords Register buffer to write
+ * @v offset Register offset
+ */
+static void linda_writeq ( struct linda *linda, const uint32_t *dwords,
+ unsigned long offset ) {
+ void *addr = ( linda->regs + offset );
+
+ DBGIO ( "[%08lx] <= %08lx%08lx\n",
+ virt_to_phys ( addr ), dwords[1], dwords[0] );
+
+ __asm__ __volatile__ ( "movq (%0), %%mm0\n\t"
+ "movq %%mm0, (%1)\n\t"
+ : : "r" ( dwords ), "r" ( addr ) : "memory" );
+}
+#define linda_writeq( _linda, _ptr, _offset ) \
+ linda_writeq ( (_linda), (_ptr)->u.dwords, (_offset) )
+#define linda_writeq_array8b( _linda, _ptr, _offset, _idx ) \
+ linda_writeq ( (_linda), (_ptr), ( (_offset) + ( (_idx) * 8 ) ) )
+#define linda_writeq_array64k( _linda, _ptr, _offset, _idx ) \
+ linda_writeq ( (_linda), (_ptr), ( (_offset) + ( (_idx) * 65536 ) ) )
+
+/**
+ * Write Linda dword register
+ *
+ * @v linda Linda device
+ * @v dword Value to write
+ * @v offset Register offset
+ */
+static void linda_writel ( struct linda *linda, uint32_t dword,
+ unsigned long offset ) {
+ writel ( dword, ( linda->regs + offset ) );
+}
+
+/***************************************************************************
+ *
+ * Link state management
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Textual representation of link state
+ *
+ * @v link_state Link state
+ * @ret link_text Link state text
+ */
+static const char * linda_link_state_text ( unsigned int link_state ) {
+ switch ( link_state ) {
+ case LINDA_LINK_STATE_DOWN: return "DOWN";
+ case LINDA_LINK_STATE_INIT: return "INIT";
+ case LINDA_LINK_STATE_ARM: return "ARM";
+ case LINDA_LINK_STATE_ACTIVE: return "ACTIVE";
+ case LINDA_LINK_STATE_ACT_DEFER:return "ACT_DEFER";
+ default: return "UNKNOWN";
+ }
+}
+
+/**
+ * Handle link state change
+ *
+ * @v linda Linda device
+ */
+static void linda_link_state_changed ( struct ib_device *ibdev ) {
+ struct linda *linda = ib_get_drvdata ( ibdev );
+ struct QIB_7220_IBCStatus ibcstatus;
+ struct QIB_7220_EXTCtrl extctrl;
+ unsigned int link_state;
+ unsigned int link_width;
+ unsigned int link_speed;
+
+ /* Read link state */
+ linda_readq ( linda, &ibcstatus, QIB_7220_IBCStatus_offset );
+ link_state = BIT_GET ( &ibcstatus, LinkState );
+ link_width = BIT_GET ( &ibcstatus, LinkWidthActive );
+ link_speed = BIT_GET ( &ibcstatus, LinkSpeedActive );
+ DBGC ( linda, "Linda %p link state %s (%s %s)\n", linda,
+ linda_link_state_text ( link_state ),
+ ( link_speed ? "DDR" : "SDR" ), ( link_width ? "x4" : "x1" ) );
+
+ /* Set LEDs according to link state */
+ linda_readq ( linda, &extctrl, QIB_7220_EXTCtrl_offset );
+ BIT_SET ( &extctrl, LEDPriPortGreenOn,
+ ( ( link_state >= LINDA_LINK_STATE_INIT ) ? 1 : 0 ) );
+ BIT_SET ( &extctrl, LEDPriPortYellowOn,
+ ( ( link_state >= LINDA_LINK_STATE_ACTIVE ) ? 1 : 0 ) );
+ linda_writeq ( linda, &extctrl, QIB_7220_EXTCtrl_offset );
+
+ /* Notify Infiniband core of link state change */
+ ibdev->port_state = ( link_state + 1 );
+ ibdev->link_width =
+ ( link_width ? IB_LINK_WIDTH_4X : IB_LINK_WIDTH_1X );
+ ibdev->link_speed =
+ ( link_speed ? IB_LINK_SPEED_DDR : IB_LINK_SPEED_SDR );
+ ib_link_state_changed ( ibdev );
+}
+
+/**
+ * Set port information
+ *
+ * @v ibdev Infiniband device
+ * @v port_info New port information
+ */
+static int linda_set_port_info ( struct ib_device *ibdev,
+ const struct ib_port_info *port_info ) {
+ struct linda *linda = ib_get_drvdata ( ibdev );
+ struct QIB_7220_IBCCtrl ibcctrl;
+ unsigned int port_state;
+ unsigned int link_state;
+
+ /* Set new link state */
+ port_state = ( port_info->link_speed_supported__port_state & 0xf );
+ if ( port_state ) {
+ link_state = ( port_state - 1 );
+ DBGC ( linda, "Linda %p set link state to %s (%x)\n", linda,
+ linda_link_state_text ( link_state ), link_state );
+ linda_readq ( linda, &ibcctrl, QIB_7220_IBCCtrl_offset );
+ BIT_SET ( &ibcctrl, LinkCmd, link_state );
+ linda_writeq ( linda, &ibcctrl, QIB_7220_IBCCtrl_offset );
+ }
+
+ /* Detect and report link state change */
+ linda_link_state_changed ( ibdev );
+
+ return 0;
+}
+
+/** Linda subnet management operations */
+static struct ib_sma_operations linda_sma_operations = {
+ .set_port_info = linda_set_port_info,
+};
+
+/***************************************************************************
+ *
+ * Context allocation
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Map context number to QPN
+ *
+ * @v ctx Context index
+ * @ret qpn Queue pair number
+ */
+static int linda_ctx_to_qpn ( unsigned int ctx ) {
+ /* This mapping is fixed by hardware */
+ return ( ctx * 2 );
+}
+
+/**
+ * Map QPN to context number
+ *
+ * @v qpn Queue pair number
+ * @ret ctx Context index
+ */
+static int linda_qpn_to_ctx ( unsigned int qpn ) {
+ /* This mapping is fixed by hardware */
+ return ( qpn / 2 );
+}
+
+/**
+ * Allocate a context
+ *
+ * @v linda Linda device
+ * @ret ctx Context index, or negative error
+ */
+static int linda_alloc_ctx ( struct linda *linda ) {
+ unsigned int ctx;
+
+ for ( ctx = 0 ; ctx < LINDA_NUM_CONTEXTS ; ctx++ ) {
+
+ if ( ! linda->used_ctx[ctx] ) {
+ linda->used_ctx[ctx ] = 1;
+ DBGC2 ( linda, "Linda %p CTX %d allocated\n",
+ linda, ctx );
+ return ctx;
+ }
+ }
+
+ DBGC ( linda, "Linda %p out of available contexts\n", linda );
+ return -ENOENT;
+}
+
+/**
+ * Free a context
+ *
+ * @v linda Linda device
+ * @v ctx Context index
+ */
+static void linda_free_ctx ( struct linda *linda, unsigned int ctx ) {
+
+ linda->used_ctx[ctx] = 0;
+ DBGC2 ( linda, "Linda %p CTX %d freed\n", linda, ctx );
+}
+
+/***************************************************************************
+ *
+ * Send datapath
+ *
+ ***************************************************************************
+ */
+
+/** Send buffer toggle bit
+ *
+ * We encode send buffers as 7 bits of send buffer index plus a single
+ * bit which should match the "check" bit in the SendBufAvail array.
+ */
+#define LINDA_SEND_BUF_TOGGLE 0x80
+
+/**
+ * Allocate a send buffer
+ *
+ * @v linda Linda device
+ * @ret send_buf Send buffer
+ *
+ * You must guarantee that a send buffer is available. This is done
+ * by refusing to allocate more TX WQEs in total than the number of
+ * available send buffers.
+ */
+static unsigned int linda_alloc_send_buf ( struct linda *linda ) {
+ unsigned int send_buf;
+
+ send_buf = linda->send_buf[linda->send_buf_cons];
+ send_buf ^= LINDA_SEND_BUF_TOGGLE;
+ linda->send_buf_cons = ( ( linda->send_buf_cons + 1 ) %
+ LINDA_MAX_SEND_BUFS );
+ return send_buf;
+}
+
+/**
+ * Free a send buffer
+ *
+ * @v linda Linda device
+ * @v send_buf Send buffer
+ */
+static void linda_free_send_buf ( struct linda *linda,
+ unsigned int send_buf ) {
+ linda->send_buf[linda->send_buf_prod] = send_buf;
+ linda->send_buf_prod = ( ( linda->send_buf_prod + 1 ) %
+ LINDA_MAX_SEND_BUFS );
+}
+
+/**
+ * Check to see if send buffer is in use
+ *
+ * @v linda Linda device
+ * @v send_buf Send buffer
+ * @ret in_use Send buffer is in use
+ */
+static int linda_send_buf_in_use ( struct linda *linda,
+ unsigned int send_buf ) {
+ unsigned int send_idx;
+ unsigned int send_check;
+ unsigned int inusecheck;
+ unsigned int inuse;
+ unsigned int check;
+
+ send_idx = ( send_buf & ~LINDA_SEND_BUF_TOGGLE );
+ send_check = ( !! ( send_buf & LINDA_SEND_BUF_TOGGLE ) );
+ inusecheck = BIT_GET ( linda->sendbufavail, InUseCheck[send_idx] );
+ inuse = ( !! ( inusecheck & 0x02 ) );
+ check = ( !! ( inusecheck & 0x01 ) );
+ return ( inuse || ( check != send_check ) );
+}
+
+/**
+ * Calculate starting offset for send buffer
+ *
+ * @v linda Linda device
+ * @v send_buf Send buffer
+ * @ret offset Starting offset
+ */
+static unsigned long linda_send_buffer_offset ( struct linda *linda,
+ unsigned int send_buf ) {
+ return ( linda->send_buffer_base +
+ ( ( send_buf & ~LINDA_SEND_BUF_TOGGLE ) *
+ LINDA_SEND_BUF_SIZE ) );
+}
+
+/**
+ * Create send work queue
+ *
+ * @v linda Linda device
+ * @v qp Queue pair
+ */
+static int linda_create_send_wq ( struct linda *linda,
+ struct ib_queue_pair *qp ) {
+ struct ib_work_queue *wq = &qp->send;
+ struct linda_send_work_queue *linda_wq = ib_wq_get_drvdata ( wq );
+ int rc;
+
+ /* Reserve send buffers */
+ if ( ( linda->reserved_send_bufs + qp->send.num_wqes ) >
+ LINDA_MAX_SEND_BUFS ) {
+ DBGC ( linda, "Linda %p out of send buffers (have %d, used "
+ "%d, need %d)\n", linda, LINDA_MAX_SEND_BUFS,
+ linda->reserved_send_bufs, qp->send.num_wqes );
+ rc = -ENOBUFS;
+ goto err_reserve_bufs;
+ }
+ linda->reserved_send_bufs += qp->send.num_wqes;
+
+ /* Reset work queue */
+ linda_wq->prod = 0;
+ linda_wq->cons = 0;
+
+ /* Allocate space for send buffer uasge list */
+ linda_wq->send_buf = zalloc ( qp->send.num_wqes *
+ sizeof ( linda_wq->send_buf[0] ) );
+ if ( ! linda_wq->send_buf ) {
+ rc = -ENOBUFS;
+ goto err_alloc_send_buf;
+ }
+
+ return 0;
+
+ free ( linda_wq->send_buf );
+ err_alloc_send_buf:
+ linda->reserved_send_bufs -= qp->send.num_wqes;
+ err_reserve_bufs:
+ return rc;
+}
+
+/**
+ * Destroy send work queue
+ *
+ * @v linda Linda device
+ * @v qp Queue pair
+ */
+static void linda_destroy_send_wq ( struct linda *linda,
+ struct ib_queue_pair *qp ) {
+ struct ib_work_queue *wq = &qp->send;
+ struct linda_send_work_queue *linda_wq = ib_wq_get_drvdata ( wq );
+
+ free ( linda_wq->send_buf );
+ linda->reserved_send_bufs -= qp->send.num_wqes;
+}
+
+/**
+ * Initialise send datapath
+ *
+ * @v linda Linda device
+ * @ret rc Return status code
+ */
+static int linda_init_send ( struct linda *linda ) {
+ struct QIB_7220_SendBufBase sendbufbase;
+ struct QIB_7220_SendBufAvailAddr sendbufavailaddr;
+ struct QIB_7220_SendCtrl sendctrl;
+ unsigned int i;
+ int rc;
+
+ /* Retrieve SendBufBase */
+ linda_readq ( linda, &sendbufbase, QIB_7220_SendBufBase_offset );
+ linda->send_buffer_base = BIT_GET ( &sendbufbase,
+ BaseAddr_SmallPIO );
+ DBGC ( linda, "Linda %p send buffers at %lx\n",
+ linda, linda->send_buffer_base );
+
+ /* Initialise the send_buf[] array */
+ for ( i = 0 ; i < LINDA_MAX_SEND_BUFS ; i++ )
+ linda->send_buf[i] = i;
+
+ /* Allocate space for the SendBufAvail array */
+ linda->sendbufavail = malloc_dma ( sizeof ( *linda->sendbufavail ),
+ LINDA_SENDBUFAVAIL_ALIGN );
+ if ( ! linda->sendbufavail ) {
+ rc = -ENOMEM;
+ goto err_alloc_sendbufavail;
+ }
+ memset ( linda->sendbufavail, 0, sizeof ( linda->sendbufavail ) );
+
+ /* Program SendBufAvailAddr into the hardware */
+ memset ( &sendbufavailaddr, 0, sizeof ( sendbufavailaddr ) );
+ BIT_FILL_1 ( &sendbufavailaddr, SendBufAvailAddr,
+ ( virt_to_bus ( linda->sendbufavail ) >> 6 ) );
+ linda_writeq ( linda, &sendbufavailaddr,
+ QIB_7220_SendBufAvailAddr_offset );
+
+ /* Enable sending and DMA of SendBufAvail */
+ memset ( &sendctrl, 0, sizeof ( sendctrl ) );
+ BIT_FILL_2 ( &sendctrl,
+ SendBufAvailUpd, 1,
+ SPioEnable, 1 );
+ linda_writeq ( linda, &sendctrl, QIB_7220_SendCtrl_offset );
+
+ return 0;
+
+ free_dma ( linda->sendbufavail, sizeof ( *linda->sendbufavail ) );
+ err_alloc_sendbufavail:
+ return rc;
+}
+
+/**
+ * Shut down send datapath
+ *
+ * @v linda Linda device
+ */
+static void linda_fini_send ( struct linda *linda ) {
+ struct QIB_7220_SendCtrl sendctrl;
+
+ /* Disable sending and DMA of SendBufAvail */
+ memset ( &sendctrl, 0, sizeof ( sendctrl ) );
+ linda_writeq ( linda, &sendctrl, QIB_7220_SendCtrl_offset );
+ mb();
+
+ /* Ensure hardware has seen this disable */
+ linda_readq ( linda, &sendctrl, QIB_7220_SendCtrl_offset );
+
+ free_dma ( linda->sendbufavail, sizeof ( *linda->sendbufavail ) );
+}
+
+/***************************************************************************
+ *
+ * Receive datapath
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Create receive work queue
+ *
+ * @v linda Linda device
+ * @v qp Queue pair
+ * @ret rc Return status code
+ */
+static int linda_create_recv_wq ( struct linda *linda,
+ struct ib_queue_pair *qp ) {
+ struct ib_work_queue *wq = &qp->recv;
+ struct linda_recv_work_queue *linda_wq = ib_wq_get_drvdata ( wq );
+ struct QIB_7220_RcvHdrAddr0 rcvhdraddr;
+ struct QIB_7220_RcvHdrTailAddr0 rcvhdrtailaddr;
+ struct QIB_7220_RcvHdrHead0 rcvhdrhead;
+ struct QIB_7220_scalar rcvegrindexhead;
+ struct QIB_7220_RcvCtrl rcvctrl;
+ unsigned int ctx = linda_qpn_to_ctx ( qp->qpn );
+ int rc;
+
+ /* Reset context information */
+ memset ( &linda_wq->header_prod, 0,
+ sizeof ( linda_wq->header_prod ) );
+ linda_wq->header_cons = 0;
+ linda_wq->eager_prod = 0;
+ linda_wq->eager_cons = 0;
+
+ /* Allocate receive header buffer */
+ linda_wq->header = malloc_dma ( LINDA_RECV_HEADERS_SIZE,
+ LINDA_RECV_HEADERS_ALIGN );
+ if ( ! linda_wq->header ) {
+ rc = -ENOMEM;
+ goto err_alloc_header;
+ }
+
+ /* Enable context in hardware */
+ memset ( &rcvhdraddr, 0, sizeof ( rcvhdraddr ) );
+ BIT_FILL_1 ( &rcvhdraddr, RcvHdrAddr0,
+ ( virt_to_bus ( linda_wq->header ) >> 2 ) );
+ linda_writeq_array8b ( linda, &rcvhdraddr,
+ QIB_7220_RcvHdrAddr0_offset, ctx );
+ memset ( &rcvhdrtailaddr, 0, sizeof ( rcvhdrtailaddr ) );
+ BIT_FILL_1 ( &rcvhdrtailaddr, RcvHdrTailAddr0,
+ ( virt_to_bus ( &linda_wq->header_prod ) >> 2 ) );
+ linda_writeq_array8b ( linda, &rcvhdrtailaddr,
+ QIB_7220_RcvHdrTailAddr0_offset, ctx );
+ memset ( &rcvhdrhead, 0, sizeof ( rcvhdrhead ) );
+ BIT_FILL_1 ( &rcvhdrhead, counter, 1 );
+ linda_writeq_array64k ( linda, &rcvhdrhead,
+ QIB_7220_RcvHdrHead0_offset, ctx );
+ memset ( &rcvegrindexhead, 0, sizeof ( rcvegrindexhead ) );
+ BIT_FILL_1 ( &rcvegrindexhead, Value, 1 );
+ linda_writeq_array64k ( linda, &rcvegrindexhead,
+ QIB_7220_RcvEgrIndexHead0_offset, ctx );
+ linda_readq ( linda, &rcvctrl, QIB_7220_RcvCtrl_offset );
+ BIT_SET ( &rcvctrl, PortEnable[ctx], 1 );
+ BIT_SET ( &rcvctrl, IntrAvail[ctx], 1 );
+ linda_writeq ( linda, &rcvctrl, QIB_7220_RcvCtrl_offset );
+
+ DBGC ( linda, "Linda %p QPN %ld CTX %d hdrs [%lx,%lx) prod %lx\n",
+ linda, qp->qpn, ctx, virt_to_bus ( linda_wq->header ),
+ ( virt_to_bus ( linda_wq->header ) + LINDA_RECV_HEADERS_SIZE ),
+ virt_to_bus ( &linda_wq->header_prod ) );
+ return 0;
+
+ free_dma ( linda_wq->header, LINDA_RECV_HEADERS_SIZE );
+ err_alloc_header:
+ return rc;
+}
+
+/**
+ * Destroy receive work queue
+ *
+ * @v linda Linda device
+ * @v qp Queue pair
+ */
+static void linda_destroy_recv_wq ( struct linda *linda,
+ struct ib_queue_pair *qp ) {
+ struct ib_work_queue *wq = &qp->recv;
+ struct linda_recv_work_queue *linda_wq = ib_wq_get_drvdata ( wq );
+ struct QIB_7220_RcvCtrl rcvctrl;
+ unsigned int ctx = linda_qpn_to_ctx ( qp->qpn );
+
+ /* Disable context in hardware */
+ linda_readq ( linda, &rcvctrl, QIB_7220_RcvCtrl_offset );
+ BIT_SET ( &rcvctrl, PortEnable[ctx], 0 );
+ BIT_SET ( &rcvctrl, IntrAvail[ctx], 0 );
+ linda_writeq ( linda, &rcvctrl, QIB_7220_RcvCtrl_offset );
+
+ /* Make sure the hardware has seen that the context is disabled */
+ linda_readq ( linda, &rcvctrl, QIB_7220_RcvCtrl_offset );
+ mb();
+
+ /* Free headers ring */
+ free_dma ( linda_wq->header, LINDA_RECV_HEADERS_SIZE );
+
+ /* Free context */
+ linda_free_ctx ( linda, ctx );
+}
+
+/**
+ * Initialise receive datapath
+ *
+ * @v linda Linda device
+ * @ret rc Return status code
+ */
+static int linda_init_recv ( struct linda *linda ) {
+ struct QIB_7220_RcvCtrl rcvctrl;
+ struct QIB_7220_scalar rcvegrbase;
+ struct QIB_7220_scalar rcvhdrentsize;
+ struct QIB_7220_scalar rcvhdrcnt;
+ struct QIB_7220_RcvBTHQP rcvbthqp;
+ unsigned int portcfg;
+ unsigned long egrbase;
+ unsigned int eager_array_size_0;
+ unsigned int eager_array_size_other;
+ unsigned int ctx;
+
+ /* Select configuration based on number of contexts */
+ switch ( LINDA_NUM_CONTEXTS ) {
+ case 5:
+ portcfg = LINDA_PORTCFG_5CTX;
+ eager_array_size_0 = LINDA_EAGER_ARRAY_SIZE_5CTX_0;
+ eager_array_size_other = LINDA_EAGER_ARRAY_SIZE_5CTX_OTHER;
+ break;
+ case 9:
+ portcfg = LINDA_PORTCFG_9CTX;
+ eager_array_size_0 = LINDA_EAGER_ARRAY_SIZE_9CTX_0;
+ eager_array_size_other = LINDA_EAGER_ARRAY_SIZE_9CTX_OTHER;
+ break;
+ case 17:
+ portcfg = LINDA_PORTCFG_17CTX;
+ eager_array_size_0 = LINDA_EAGER_ARRAY_SIZE_17CTX_0;
+ eager_array_size_other = LINDA_EAGER_ARRAY_SIZE_17CTX_OTHER;
+ break;
+ default:
+ linker_assert ( 0, invalid_LINDA_NUM_CONTEXTS );
+ return -EINVAL;
+ }
+
+ /* Configure number of contexts */
+ memset ( &rcvctrl, 0, sizeof ( rcvctrl ) );
+ BIT_FILL_3 ( &rcvctrl,
+ TailUpd, 1,
+ PortCfg, portcfg,
+ RcvQPMapEnable, 1 );
+ linda_writeq ( linda, &rcvctrl, QIB_7220_RcvCtrl_offset );
+
+ /* Configure receive header buffer sizes */
+ memset ( &rcvhdrcnt, 0, sizeof ( rcvhdrcnt ) );
+ BIT_FILL_1 ( &rcvhdrcnt, Value, LINDA_RECV_HEADER_COUNT );
+ linda_writeq ( linda, &rcvhdrcnt, QIB_7220_RcvHdrCnt_offset );
+ memset ( &rcvhdrentsize, 0, sizeof ( rcvhdrentsize ) );
+ BIT_FILL_1 ( &rcvhdrentsize, Value, ( LINDA_RECV_HEADER_SIZE >> 2 ) );
+ linda_writeq ( linda, &rcvhdrentsize, QIB_7220_RcvHdrEntSize_offset );
+
+ /* Calculate eager array start addresses for each context */
+ linda_readq ( linda, &rcvegrbase, QIB_7220_RcvEgrBase_offset );
+ egrbase = BIT_GET ( &rcvegrbase, Value );
+ linda->recv_wq[0].eager_array = egrbase;
+ linda->recv_wq[0].eager_entries = eager_array_size_0;
+ egrbase += ( eager_array_size_0 * sizeof ( struct QIB_7220_RcvEgr ) );
+ for ( ctx = 1 ; ctx < LINDA_NUM_CONTEXTS ; ctx++ ) {
+ linda->recv_wq[ctx].eager_array = egrbase;
+ linda->recv_wq[ctx].eager_entries = eager_array_size_other;
+ egrbase += ( eager_array_size_other *
+ sizeof ( struct QIB_7220_RcvEgr ) );
+ }
+ for ( ctx = 0 ; ctx < LINDA_NUM_CONTEXTS ; ctx++ ) {
+ DBGC ( linda, "Linda %p CTX %d eager array at %lx (%d "
+ "entries)\n", linda, ctx,
+ linda->recv_wq[ctx].eager_array,
+ linda->recv_wq[ctx].eager_entries );
+ }
+
+ /* Set the BTH QP for Infinipath packets to an unused value */
+ memset ( &rcvbthqp, 0, sizeof ( rcvbthqp ) );
+ BIT_FILL_1 ( &rcvbthqp, RcvBTHQP, LINDA_QP_IDETH );
+ linda_writeq ( linda, &rcvbthqp, QIB_7220_RcvBTHQP_offset );
+
+ return 0;
+}
+
+/**
+ * Shut down receive datapath
+ *
+ * @v linda Linda device
+ */
+static void linda_fini_recv ( struct linda *linda __unused ) {
+ /* Nothing to do; all contexts were already disabled when the
+ * queue pairs were destroyed
+ */
+}
+
+/***************************************************************************
+ *
+ * Completion queue operations
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Create completion queue
+ *
+ * @v ibdev Infiniband device
+ * @v cq Completion queue
+ * @ret rc Return status code
+ */
+static int linda_create_cq ( struct ib_device *ibdev,
+ struct ib_completion_queue *cq ) {
+ struct linda *linda = ib_get_drvdata ( ibdev );
+ static int cqn;
+
+ /* The hardware has no concept of completion queues. We
+ * simply use the association between CQs and WQs (already
+ * handled by the IB core) to decide which WQs to poll.
+ *
+ * We do set a CQN, just to avoid confusing debug messages
+ * from the IB core.
+ */
+ cq->cqn = ++cqn;
+ DBGC ( linda, "Linda %p CQN %ld created\n", linda, cq->cqn );
+
+ return 0;
+}
+
+/**
+ * Destroy completion queue
+ *
+ * @v ibdev Infiniband device
+ * @v cq Completion queue
+ */
+static void linda_destroy_cq ( struct ib_device *ibdev,
+ struct ib_completion_queue *cq ) {
+ struct linda *linda = ib_get_drvdata ( ibdev );
+
+ /* Nothing to do */
+ DBGC ( linda, "Linda %p CQN %ld destroyed\n", linda, cq->cqn );
+}
+
+/***************************************************************************
+ *
+ * Queue pair operations
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Create queue pair
+ *
+ * @v ibdev Infiniband device
+ * @v qp Queue pair
+ * @ret rc Return status code
+ */
+static int linda_create_qp ( struct ib_device *ibdev,
+ struct ib_queue_pair *qp ) {
+ struct linda *linda = ib_get_drvdata ( ibdev );
+ int ctx;
+ int rc;
+
+ /* Locate an available context */
+ ctx = linda_alloc_ctx ( linda );
+ if ( ctx < 0 ) {
+ rc = ctx;
+ goto err_alloc_ctx;
+ }
+
+ /* Set queue pair number based on context index */
+ qp->qpn = linda_ctx_to_qpn ( ctx );
+
+ /* Set work-queue private data pointers */
+ ib_wq_set_drvdata ( &qp->send, &linda->send_wq[ctx] );
+ ib_wq_set_drvdata ( &qp->recv, &linda->recv_wq[ctx] );
+
+ /* Create receive work queue */
+ if ( ( rc = linda_create_recv_wq ( linda, qp ) ) != 0 )
+ goto err_create_recv_wq;
+
+ /* Create send work queue */
+ if ( ( rc = linda_create_send_wq ( linda, qp ) ) != 0 )
+ goto err_create_send_wq;
+
+ return 0;
+
+ linda_destroy_send_wq ( linda, qp );
+ err_create_send_wq:
+ linda_destroy_recv_wq ( linda, qp );
+ err_create_recv_wq:
+ linda_free_ctx ( linda, ctx );
+ err_alloc_ctx:
+ return rc;
+}
+
+/**
+ * Modify queue pair
+ *
+ * @v ibdev Infiniband device
+ * @v qp Queue pair
+ * @v mod_list Modification list
+ * @ret rc Return status code
+ */
+static int linda_modify_qp ( struct ib_device *ibdev,
+ struct ib_queue_pair *qp,
+ unsigned long mod_list __unused ) {
+ struct linda *linda = ib_get_drvdata ( ibdev );
+
+ /* Nothing to do; the hardware doesn't have a notion of queue
+ * keys
+ */
+ DBGC ( linda, "Linda %p QPN %ld modified\n", linda, qp->qpn );
+ return 0;
+}
+
+/**
+ * Destroy queue pair
+ *
+ * @v ibdev Infiniband device
+ * @v qp Queue pair
+ */
+static void linda_destroy_qp ( struct ib_device *ibdev,
+ struct ib_queue_pair *qp ) {
+ struct linda *linda = ib_get_drvdata ( ibdev );
+
+ linda_destroy_send_wq ( linda, qp );
+ linda_destroy_recv_wq ( linda, qp );
+}
+
+/***************************************************************************
+ *
+ * Work request operations
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Post send work queue entry
+ *
+ * @v ibdev Infiniband device
+ * @v qp Queue pair
+ * @v av Address vector
+ * @v iobuf I/O buffer
+ * @ret rc Return status code
+ */
+static int linda_post_send ( struct ib_device *ibdev,
+ struct ib_queue_pair *qp,
+ struct ib_address_vector *av,
+ struct io_buffer *iobuf ) {
+ struct linda *linda = ib_get_drvdata ( ibdev );
+ struct ib_work_queue *wq = &qp->send;
+ struct linda_send_work_queue *linda_wq = ib_wq_get_drvdata ( wq );
+ struct QIB_7220_SendPbc sendpbc;
+ uint8_t header_buf[IB_MAX_HEADER_SIZE];
+ struct io_buffer headers;
+ unsigned int send_buf;
+ unsigned long start_offset;
+ unsigned long offset;
+ size_t len;
+ ssize_t frag_len;
+ uint32_t *data;
+
+ /* Allocate send buffer and calculate offset */
+ send_buf = linda_alloc_send_buf ( linda );
+ start_offset = offset = linda_send_buffer_offset ( linda, send_buf );
+
+ /* Store I/O buffer and send buffer index */
+ assert ( wq->iobufs[linda_wq->prod] == NULL );
+ wq->iobufs[linda_wq->prod] = iobuf;
+ linda_wq->send_buf[linda_wq->prod] = send_buf;
+
+ /* Construct headers */
+ iob_populate ( &headers, header_buf, 0, sizeof ( header_buf ) );
+ iob_reserve ( &headers, sizeof ( header_buf ) );
+ ib_push ( ibdev, &headers, qp, iob_len ( iobuf ), av );
+
+ /* Calculate packet length */
+ len = ( ( sizeof ( sendpbc ) + iob_len ( &headers ) +
+ iob_len ( iobuf ) + 3 ) & ~3 );
+
+ /* Construct send per-buffer control word */
+ memset ( &sendpbc, 0, sizeof ( sendpbc ) );
+ BIT_FILL_2 ( &sendpbc,
+ LengthP1_toibc, ( ( len >> 2 ) - 1 ),
+ VL15, 1 );
+
+ /* Write SendPbc */
+ DBG_DISABLE ( DBGLVL_IO );
+ linda_writeq ( linda, &sendpbc, offset );
+ offset += sizeof ( sendpbc );
+
+ /* Write headers */
+ for ( data = headers.data, frag_len = iob_len ( &headers ) ;
+ frag_len > 0 ; data++, offset += 4, frag_len -= 4 ) {
+ linda_writel ( linda, *data, offset );
+ }
+
+ /* Write data */
+ for ( data = iobuf->data, frag_len = iob_len ( iobuf ) ;
+ frag_len > 0 ; data++, offset += 4, frag_len -= 4 ) {
+ linda_writel ( linda, *data, offset );
+ }
+ DBG_ENABLE ( DBGLVL_IO );
+
+ assert ( ( start_offset + len ) == offset );
+ DBGC2 ( linda, "Linda %p QPN %ld TX %d(%d) posted [%lx,%lx)\n",
+ linda, qp->qpn, send_buf, linda_wq->prod,
+ start_offset, offset );
+
+ /* Increment producer counter */
+ linda_wq->prod = ( ( linda_wq->prod + 1 ) & ( wq->num_wqes - 1 ) );
+
+ return 0;
+}
+
+/**
+ * Complete send work queue entry
+ *
+ * @v ibdev Infiniband device
+ * @v qp Queue pair
+ * @v wqe_idx Work queue entry index
+ */
+static void linda_complete_send ( struct ib_device *ibdev,
+ struct ib_queue_pair *qp,
+ unsigned int wqe_idx ) {
+ struct linda *linda = ib_get_drvdata ( ibdev );
+ struct ib_work_queue *wq = &qp->send;
+ struct linda_send_work_queue *linda_wq = ib_wq_get_drvdata ( wq );
+ struct io_buffer *iobuf;
+ unsigned int send_buf;
+
+ /* Parse completion */
+ send_buf = linda_wq->send_buf[wqe_idx];
+ DBGC2 ( linda, "Linda %p QPN %ld TX %d(%d) complete\n",
+ linda, qp->qpn, send_buf, wqe_idx );
+
+ /* Complete work queue entry */
+ iobuf = wq->iobufs[wqe_idx];
+ assert ( iobuf != NULL );
+ ib_complete_send ( ibdev, qp, iobuf, 0 );
+ wq->iobufs[wqe_idx] = NULL;
+
+ /* Free send buffer */
+ linda_free_send_buf ( linda, send_buf );
+}
+
+/**
+ * Poll send work queue
+ *
+ * @v ibdev Infiniband device
+ * @v qp Queue pair
+ */
+static void linda_poll_send_wq ( struct ib_device *ibdev,
+ struct ib_queue_pair *qp ) {
+ struct linda *linda = ib_get_drvdata ( ibdev );
+ struct ib_work_queue *wq = &qp->send;
+ struct linda_send_work_queue *linda_wq = ib_wq_get_drvdata ( wq );
+ unsigned int send_buf;
+
+ /* Look for completions */
+ while ( wq->fill ) {
+
+ /* Check to see if send buffer has completed */
+ send_buf = linda_wq->send_buf[linda_wq->cons];
+ if ( linda_send_buf_in_use ( linda, send_buf ) )
+ break;
+
+ /* Complete this buffer */
+ linda_complete_send ( ibdev, qp, linda_wq->cons );
+
+ /* Increment consumer counter */
+ linda_wq->cons = ( ( linda_wq->cons + 1 ) &
+ ( wq->num_wqes - 1 ) );
+ }
+}
+
+/**
+ * Post receive work queue entry
+ *
+ * @v ibdev Infiniband device
+ * @v qp Queue pair
+ * @v iobuf I/O buffer
+ * @ret rc Return status code
+ */
+static int linda_post_recv ( struct ib_device *ibdev,
+ struct ib_queue_pair *qp,
+ struct io_buffer *iobuf ) {
+ struct linda *linda = ib_get_drvdata ( ibdev );
+ struct ib_work_queue *wq = &qp->recv;
+ struct linda_recv_work_queue *linda_wq = ib_wq_get_drvdata ( wq );
+ struct QIB_7220_RcvEgr rcvegr;
+ struct QIB_7220_scalar rcvegrindexhead;
+ unsigned int ctx = linda_qpn_to_ctx ( qp->qpn );
+ physaddr_t addr;
+ size_t len;
+ unsigned int wqe_idx;
+ unsigned int bufsize;
+
+ /* Sanity checks */
+ addr = virt_to_bus ( iobuf->data );
+ len = iob_tailroom ( iobuf );
+ if ( addr & ( LINDA_EAGER_BUFFER_ALIGN - 1 ) ) {
+ DBGC ( linda, "Linda %p QPN %ld misaligned RX buffer "
+ "(%08lx)\n", linda, qp->qpn, addr );
+ return -EINVAL;
+ }
+ if ( len != LINDA_RECV_PAYLOAD_SIZE ) {
+ DBGC ( linda, "Linda %p QPN %ld wrong RX buffer size (%d)\n",
+ linda, qp->qpn, len );
+ return -EINVAL;
+ }
+
+ /* Calculate eager producer index and WQE index */
+ wqe_idx = ( linda_wq->eager_prod & ( wq->num_wqes - 1 ) );
+ assert ( wq->iobufs[wqe_idx] == NULL );
+
+ /* Store I/O buffer */
+ wq->iobufs[wqe_idx] = iobuf;
+
+ /* Calculate buffer size */
+ switch ( LINDA_RECV_PAYLOAD_SIZE ) {
+ case 2048: bufsize = LINDA_EAGER_BUFFER_2K; break;
+ case 4096: bufsize = LINDA_EAGER_BUFFER_4K; break;
+ case 8192: bufsize = LINDA_EAGER_BUFFER_8K; break;
+ case 16384: bufsize = LINDA_EAGER_BUFFER_16K; break;
+ case 32768: bufsize = LINDA_EAGER_BUFFER_32K; break;
+ case 65536: bufsize = LINDA_EAGER_BUFFER_64K; break;
+ default: linker_assert ( 0, invalid_rx_payload_size );
+ bufsize = LINDA_EAGER_BUFFER_NONE;
+ }
+
+ /* Post eager buffer */
+ memset ( &rcvegr, 0, sizeof ( rcvegr ) );
+ BIT_FILL_2 ( &rcvegr,
+ Addr, ( addr >> 11 ),
+ BufSize, bufsize );
+ linda_writeq_array8b ( linda, &rcvegr,
+ linda_wq->eager_array, linda_wq->eager_prod );
+ DBGC2 ( linda, "Linda %p QPN %ld RX egr %d(%d) posted [%lx,%lx)\n",
+ linda, qp->qpn, linda_wq->eager_prod, wqe_idx,
+ addr, ( addr + len ) );
+
+ /* Increment producer index */
+ linda_wq->eager_prod = ( ( linda_wq->eager_prod + 1 ) &
+ ( linda_wq->eager_entries - 1 ) );
+
+ /* Update head index */
+ memset ( &rcvegrindexhead, 0, sizeof ( rcvegrindexhead ) );
+ BIT_FILL_1 ( &rcvegrindexhead,
+ Value, ( ( linda_wq->eager_prod + 1 ) &
+ ( linda_wq->eager_entries - 1 ) ) );
+ linda_writeq_array64k ( linda, &rcvegrindexhead,
+ QIB_7220_RcvEgrIndexHead0_offset, ctx );
+
+ return 0;
+}
+
+/**
+ * Complete receive work queue entry
+ *
+ * @v ibdev Infiniband device
+ * @v qp Queue pair
+ * @v header_offs Header offset
+ */
+static void linda_complete_recv ( struct ib_device *ibdev,
+ struct ib_queue_pair *qp,
+ unsigned int header_offs ) {
+ struct linda *linda = ib_get_drvdata ( ibdev );
+ struct ib_work_queue *wq = &qp->recv;
+ struct linda_recv_work_queue *linda_wq = ib_wq_get_drvdata ( wq );
+ struct QIB_7220_RcvHdrFlags *rcvhdrflags;
+ struct QIB_7220_RcvEgr rcvegr;
+ struct io_buffer headers;
+ struct io_buffer *iobuf;
+ struct ib_queue_pair *intended_qp;
+ struct ib_address_vector av;
+ unsigned int rcvtype;
+ unsigned int pktlen;
+ unsigned int egrindex;
+ unsigned int useegrbfr;
+ unsigned int iberr, mkerr, tiderr, khdrerr, mtuerr;
+ unsigned int lenerr, parityerr, vcrcerr, icrcerr;
+ unsigned int err;
+ unsigned int hdrqoffset;
+ unsigned int header_len;
+ unsigned int padded_payload_len;
+ unsigned int wqe_idx;
+ size_t payload_len;
+ int qp0;
+ int rc;
+
+ /* RcvHdrFlags are at the end of the header entry */
+ rcvhdrflags = ( linda_wq->header + header_offs +
+ LINDA_RECV_HEADER_SIZE - sizeof ( *rcvhdrflags ) );
+ rcvtype = BIT_GET ( rcvhdrflags, RcvType );
+ pktlen = ( BIT_GET ( rcvhdrflags, PktLen ) << 2 );
+ egrindex = BIT_GET ( rcvhdrflags, EgrIndex );
+ useegrbfr = BIT_GET ( rcvhdrflags, UseEgrBfr );
+ hdrqoffset = ( BIT_GET ( rcvhdrflags, HdrqOffset ) << 2 );
+ iberr = BIT_GET ( rcvhdrflags, IBErr );
+ mkerr = BIT_GET ( rcvhdrflags, MKErr );
+ tiderr = BIT_GET ( rcvhdrflags, TIDErr );
+ khdrerr = BIT_GET ( rcvhdrflags, KHdrErr );
+ mtuerr = BIT_GET ( rcvhdrflags, MTUErr );
+ lenerr = BIT_GET ( rcvhdrflags, LenErr );
+ parityerr = BIT_GET ( rcvhdrflags, ParityErr );
+ vcrcerr = BIT_GET ( rcvhdrflags, VCRCErr );
+ icrcerr = BIT_GET ( rcvhdrflags, ICRCErr );
+ header_len = ( LINDA_RECV_HEADER_SIZE - hdrqoffset -
+ sizeof ( *rcvhdrflags ) );
+ padded_payload_len = ( pktlen - header_len - 4 /* ICRC */ );
+ err = ( iberr | mkerr | tiderr | khdrerr | mtuerr |
+ lenerr | parityerr | vcrcerr | icrcerr );
+ /* IB header is placed immediately before RcvHdrFlags */
+ iob_populate ( &headers, ( ( ( void * ) rcvhdrflags ) - header_len ),
+ header_len, header_len );
+
+ /* Dump diagnostic information */
+ if ( err || ( ! useegrbfr ) ) {
+ DBGC ( linda, "Linda %p QPN %ld RX egr %d%s hdr %d type %d "
+ "len %d(%d+%d+4)%s%s%s%s%s%s%s%s%s%s%s\n", linda,
+ qp->qpn, egrindex, ( useegrbfr ? "" : "(unused)" ),
+ ( header_offs / LINDA_RECV_HEADER_SIZE ), rcvtype,
+ pktlen, header_len, padded_payload_len,
+ ( err ? " [Err" : "" ), ( iberr ? " IB" : "" ),
+ ( mkerr ? " MK" : "" ), ( tiderr ? " TID" : "" ),
+ ( khdrerr ? " KHdr" : "" ), ( mtuerr ? " MTU" : "" ),
+ ( lenerr ? " Len" : "" ), ( parityerr ? " Parity" : ""),
+ ( vcrcerr ? " VCRC" : "" ), ( icrcerr ? " ICRC" : "" ),
+ ( err ? "]" : "" ) );
+ } else {
+ DBGC2 ( linda, "Linda %p QPN %ld RX egr %d hdr %d type %d "
+ "len %d(%d+%d+4)\n", linda, qp->qpn, egrindex,
+ ( header_offs / LINDA_RECV_HEADER_SIZE ), rcvtype,
+ pktlen, header_len, padded_payload_len );
+ }
+ DBGCP_HDA ( linda, hdrqoffset, headers.data,
+ ( header_len + sizeof ( *rcvhdrflags ) ) );
+
+ /* Parse header to generate address vector */
+ qp0 = ( qp->qpn == 0 );
+ intended_qp = NULL;
+ if ( ( rc = ib_pull ( ibdev, &headers, ( qp0 ? &intended_qp : NULL ),
+ &payload_len, &av ) ) != 0 ) {
+ DBGC ( linda, "Linda %p could not parse headers: %s\n",
+ linda, strerror ( rc ) );
+ err = 1;
+ }
+ if ( ! intended_qp )
+ intended_qp = qp;
+
+ /* Complete this buffer and any skipped buffers. Note that
+ * when the hardware runs out of buffers, it will repeatedly
+ * report the same buffer (the tail) as a TID error, and that
+ * it also has a habit of sometimes skipping over several
+ * buffers at once.
+ */
+ while ( 1 ) {
+
+ /* If we have caught up to the producer counter, stop.
+ * This will happen when the hardware first runs out
+ * of buffers and starts reporting TID errors against
+ * the eager buffer it wants to use next.
+ */
+ if ( linda_wq->eager_cons == linda_wq->eager_prod )
+ break;
+
+ /* If we have caught up to where we should be after
+ * completing this egrindex, stop. We phrase the test
+ * this way to avoid completing the entire ring when
+ * we receive the same egrindex twice in a row.
+ */
+ if ( ( linda_wq->eager_cons ==
+ ( ( egrindex + 1 ) & ( linda_wq->eager_entries - 1 ) )))
+ break;
+
+ /* Identify work queue entry and corresponding I/O
+ * buffer.
+ */
+ wqe_idx = ( linda_wq->eager_cons & ( wq->num_wqes - 1 ) );
+ iobuf = wq->iobufs[wqe_idx];
+ assert ( iobuf != NULL );
+ wq->iobufs[wqe_idx] = NULL;
+
+ /* Complete the eager buffer */
+ if ( linda_wq->eager_cons == egrindex ) {
+ /* Completing the eager buffer described in
+ * this header entry.
+ */
+ iob_put ( iobuf, payload_len );
+ rc = ( err ? -EIO : ( useegrbfr ? 0 : -ECANCELED ) );
+ /* Redirect to target QP if necessary */
+ if ( qp != intended_qp ) {
+ DBGC ( linda, "Linda %p redirecting QPN %ld "
+ "=> %ld\n",
+ linda, qp->qpn, intended_qp->qpn );
+ /* Compensate for incorrect fill levels */
+ qp->recv.fill--;
+ intended_qp->recv.fill++;
+ }
+ ib_complete_recv ( ibdev, intended_qp, &av, iobuf, rc);
+ } else {
+ /* Completing on a skipped-over eager buffer */
+ ib_complete_recv ( ibdev, qp, &av, iobuf, -ECANCELED );
+ }
+
+ /* Clear eager buffer */
+ memset ( &rcvegr, 0, sizeof ( rcvegr ) );
+ linda_writeq_array8b ( linda, &rcvegr, linda_wq->eager_array,
+ linda_wq->eager_cons );
+
+ /* Increment consumer index */
+ linda_wq->eager_cons = ( ( linda_wq->eager_cons + 1 ) &
+ ( linda_wq->eager_entries - 1 ) );
+ }
+}
+
+/**
+ * Poll receive work queue
+ *
+ * @v ibdev Infiniband device
+ * @v qp Queue pair
+ */
+static void linda_poll_recv_wq ( struct ib_device *ibdev,
+ struct ib_queue_pair *qp ) {
+ struct linda *linda = ib_get_drvdata ( ibdev );
+ struct ib_work_queue *wq = &qp->recv;
+ struct linda_recv_work_queue *linda_wq = ib_wq_get_drvdata ( wq );
+ struct QIB_7220_RcvHdrHead0 rcvhdrhead;
+ unsigned int ctx = linda_qpn_to_ctx ( qp->qpn );
+ unsigned int header_prod;
+
+ /* Check for received packets */
+ header_prod = ( BIT_GET ( &linda_wq->header_prod, Value ) << 2 );
+ if ( header_prod == linda_wq->header_cons )
+ return;
+
+ /* Process all received packets */
+ while ( linda_wq->header_cons != header_prod ) {
+
+ /* Complete the receive */
+ linda_complete_recv ( ibdev, qp, linda_wq->header_cons );
+
+ /* Increment the consumer offset */
+ linda_wq->header_cons += LINDA_RECV_HEADER_SIZE;
+ linda_wq->header_cons %= LINDA_RECV_HEADERS_SIZE;
+ }
+
+ /* Update consumer offset */
+ memset ( &rcvhdrhead, 0, sizeof ( rcvhdrhead ) );
+ BIT_FILL_2 ( &rcvhdrhead,
+ RcvHeadPointer, ( linda_wq->header_cons >> 2 ),
+ counter, 1 );
+ linda_writeq_array64k ( linda, &rcvhdrhead,
+ QIB_7220_RcvHdrHead0_offset, ctx );
+}
+
+/**
+ * Poll completion queue
+ *
+ * @v ibdev Infiniband device
+ * @v cq Completion queue
+ */
+static void linda_poll_cq ( struct ib_device *ibdev,
+ struct ib_completion_queue *cq ) {
+ struct ib_work_queue *wq;
+
+ /* Poll associated send and receive queues */
+ list_for_each_entry ( wq, &cq->work_queues, list ) {
+ if ( wq->is_send ) {
+ linda_poll_send_wq ( ibdev, wq->qp );
+ } else {
+ linda_poll_recv_wq ( ibdev, wq->qp );
+ }
+ }
+}
+
+/***************************************************************************
+ *
+ * Event queues
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Poll event queue
+ *
+ * @v ibdev Infiniband device
+ */
+static void linda_poll_eq ( struct ib_device *ibdev ) {
+ struct linda *linda = ib_get_drvdata ( ibdev );
+ struct QIB_7220_ErrStatus errstatus;
+ struct QIB_7220_ErrClear errclear;
+
+ /* Check for link status changes */
+ DBG_DISABLE ( DBGLVL_IO );
+ linda_readq ( linda, &errstatus, QIB_7220_ErrStatus_offset );
+ DBG_ENABLE ( DBGLVL_IO );
+ if ( BIT_GET ( &errstatus, IBStatusChanged ) ) {
+ linda_link_state_changed ( ibdev );
+ memset ( &errclear, 0, sizeof ( errclear ) );
+ BIT_FILL_1 ( &errclear, IBStatusChangedClear, 1 );
+ linda_writeq ( linda, &errclear, QIB_7220_ErrClear_offset );
+ }
+}
+
+/***************************************************************************
+ *
+ * Infiniband link-layer operations
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Initialise Infiniband link
+ *
+ * @v ibdev Infiniband device
+ * @ret rc Return status code
+ */
+static int linda_open ( struct ib_device *ibdev ) {
+ struct linda *linda = ib_get_drvdata ( ibdev );
+ struct QIB_7220_Control control;
+
+ /* Disable link */
+ linda_readq ( linda, &control, QIB_7220_Control_offset );
+ BIT_SET ( &control, LinkEn, 1 );
+ linda_writeq ( linda, &control, QIB_7220_Control_offset );
+ return 0;
+}
+
+/**
+ * Close Infiniband link
+ *
+ * @v ibdev Infiniband device
+ */
+static void linda_close ( struct ib_device *ibdev ) {
+ struct linda *linda = ib_get_drvdata ( ibdev );
+ struct QIB_7220_Control control;
+
+ /* Disable link */
+ linda_readq ( linda, &control, QIB_7220_Control_offset );
+ BIT_SET ( &control, LinkEn, 0 );
+ linda_writeq ( linda, &control, QIB_7220_Control_offset );
+}
+
+/***************************************************************************
+ *
+ * Multicast group operations
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Attach to multicast group
+ *
+ * @v ibdev Infiniband device
+ * @v qp Queue pair
+ * @v gid Multicast GID
+ * @ret rc Return status code
+ */
+static int linda_mcast_attach ( struct ib_device *ibdev,
+ struct ib_queue_pair *qp,
+ struct ib_gid *gid ) {
+ struct linda *linda = ib_get_drvdata ( ibdev );
+
+ ( void ) linda;
+ ( void ) qp;
+ ( void ) gid;
+ return 0;
+}
+
+/**
+ * Detach from multicast group
+ *
+ * @v ibdev Infiniband device
+ * @v qp Queue pair
+ * @v gid Multicast GID
+ */
+static void linda_mcast_detach ( struct ib_device *ibdev,
+ struct ib_queue_pair *qp,
+ struct ib_gid *gid ) {
+ struct linda *linda = ib_get_drvdata ( ibdev );
+
+ ( void ) linda;
+ ( void ) qp;
+ ( void ) gid;
+}
+
+/** Linda Infiniband operations */
+static struct ib_device_operations linda_ib_operations = {
+ .create_cq = linda_create_cq,
+ .destroy_cq = linda_destroy_cq,
+ .create_qp = linda_create_qp,
+ .modify_qp = linda_modify_qp,
+ .destroy_qp = linda_destroy_qp,
+ .post_send = linda_post_send,
+ .post_recv = linda_post_recv,
+ .poll_cq = linda_poll_cq,
+ .poll_eq = linda_poll_eq,
+ .open = linda_open,
+ .close = linda_close,
+ .mcast_attach = linda_mcast_attach,
+ .mcast_detach = linda_mcast_detach,
+};
+
+/***************************************************************************
+ *
+ * I2C bus operations
+ *
+ ***************************************************************************
+ */
+
+/** Linda I2C bit to GPIO mappings */
+static unsigned int linda_i2c_bits[] = {
+ [I2C_BIT_SCL] = ( 1 << LINDA_GPIO_SCL ),
+ [I2C_BIT_SDA] = ( 1 << LINDA_GPIO_SDA ),
+};
+
+/**
+ * Read Linda I2C line status
+ *
+ * @v basher Bit-bashing interface
+ * @v bit_id Bit number
+ * @ret zero Input is a logic 0
+ * @ret non-zero Input is a logic 1
+ */
+static int linda_i2c_read_bit ( struct bit_basher *basher,
+ unsigned int bit_id ) {
+ struct linda *linda =
+ container_of ( basher, struct linda, i2c.basher );
+ struct QIB_7220_EXTStatus extstatus;
+ unsigned int status;
+
+ DBG_DISABLE ( DBGLVL_IO );
+
+ linda_readq ( linda, &extstatus, QIB_7220_EXTStatus_offset );
+ status = ( BIT_GET ( &extstatus, GPIOIn ) & linda_i2c_bits[bit_id] );
+
+ DBG_ENABLE ( DBGLVL_IO );
+
+ return status;
+}
+
+/**
+ * Write Linda I2C line status
+ *
+ * @v basher Bit-bashing interface
+ * @v bit_id Bit number
+ * @v data Value to write
+ */
+static void linda_i2c_write_bit ( struct bit_basher *basher,
+ unsigned int bit_id, unsigned long data ) {
+ struct linda *linda =
+ container_of ( basher, struct linda, i2c.basher );
+ struct QIB_7220_EXTCtrl extctrl;
+ struct QIB_7220_GPIO gpioout;
+ unsigned int bit = linda_i2c_bits[bit_id];
+ unsigned int outputs = 0;
+ unsigned int output_enables = 0;
+
+ DBG_DISABLE ( DBGLVL_IO );
+
+ /* Read current GPIO mask and outputs */
+ linda_readq ( linda, &extctrl, QIB_7220_EXTCtrl_offset );
+ linda_readq ( linda, &gpioout, QIB_7220_GPIOOut_offset );
+
+ /* Update outputs and output enables. I2C lines are tied
+ * high, so we always set the output to 0 and use the output
+ * enable to control the line.
+ */
+ output_enables = BIT_GET ( &extctrl, GPIOOe );
+ output_enables = ( ( output_enables & ~bit ) | ( ~data & bit ) );
+ outputs = BIT_GET ( &gpioout, GPIO );
+ outputs = ( outputs & ~bit );
+ BIT_SET ( &extctrl, GPIOOe, output_enables );
+ BIT_SET ( &gpioout, GPIO, outputs );
+
+ /* Write the output enable first; that way we avoid logic
+ * hazards.
+ */
+ linda_writeq ( linda, &extctrl, QIB_7220_EXTCtrl_offset );
+ linda_writeq ( linda, &gpioout, QIB_7220_GPIOOut_offset );
+ mb();
+
+ DBG_ENABLE ( DBGLVL_IO );
+}
+
+/** Linda I2C bit-bashing interface operations */
+static struct bit_basher_operations linda_i2c_basher_ops = {
+ .read = linda_i2c_read_bit,
+ .write = linda_i2c_write_bit,
+};
+
+/**
+ * Initialise Linda I2C subsystem
+ *
+ * @v linda Linda device
+ * @ret rc Return status code
+ */
+static int linda_init_i2c ( struct linda *linda ) {
+ static int try_eeprom_address[] = { 0x51, 0x50 };
+ unsigned int i;
+ int rc;
+
+ /* Initialise bus */
+ if ( ( rc = init_i2c_bit_basher ( &linda->i2c,
+ &linda_i2c_basher_ops ) ) != 0 ) {
+ DBGC ( linda, "Linda %p could not initialise I2C bus: %s\n",
+ linda, strerror ( rc ) );
+ return rc;
+ }
+
+ /* Probe for devices */
+ for ( i = 0 ; i < ( sizeof ( try_eeprom_address ) /
+ sizeof ( try_eeprom_address[0] ) ) ; i++ ) {
+ init_i2c_eeprom ( &linda->eeprom, try_eeprom_address[i] );
+ if ( ( rc = i2c_check_presence ( &linda->i2c.i2c,
+ &linda->eeprom ) ) == 0 ) {
+ DBGC2 ( linda, "Linda %p found EEPROM at %02x\n",
+ linda, try_eeprom_address[i] );
+ return 0;
+ }
+ }
+
+ DBGC ( linda, "Linda %p could not find EEPROM\n", linda );
+ return -ENODEV;
+}
+
+/**
+ * Read EEPROM parameters
+ *
+ * @v linda Linda device
+ * @v guid GUID to fill in
+ * @ret rc Return status code
+ */
+static int linda_read_eeprom ( struct linda *linda,
+ struct ib_gid_half *guid ) {
+ struct i2c_interface *i2c = &linda->i2c.i2c;
+ int rc;
+
+ /* Read GUID */
+ if ( ( rc = i2c->read ( i2c, &linda->eeprom, LINDA_EEPROM_GUID_OFFSET,
+ guid->bytes, sizeof ( *guid ) ) ) != 0 ) {
+ DBGC ( linda, "Linda %p could not read GUID: %s\n",
+ linda, strerror ( rc ) );
+ return rc;
+ }
+ DBGC2 ( linda, "Linda %p has GUID %02x:%02x:%02x:%02x:%02x:%02x:"
+ "%02x:%02x\n", linda, guid->bytes[0], guid->bytes[1],
+ guid->bytes[2], guid->bytes[3], guid->bytes[4],
+ guid->bytes[5], guid->bytes[6], guid->bytes[7] );
+
+ /* Read serial number (debug only) */
+ if ( DBG_LOG ) {
+ uint8_t serial[LINDA_EEPROM_SERIAL_SIZE + 1];
+
+ serial[ sizeof ( serial ) - 1 ] = '\0';
+ if ( ( rc = i2c->read ( i2c, &linda->eeprom,
+ LINDA_EEPROM_SERIAL_OFFSET, serial,
+ ( sizeof ( serial ) - 1 ) ) ) != 0 ) {
+ DBGC ( linda, "Linda %p could not read serial: %s\n",
+ linda, strerror ( rc ) );
+ return rc;
+ }
+ DBGC2 ( linda, "Linda %p has serial number \"%s\"\n",
+ linda, serial );
+ }
+
+ return 0;
+}
+
+/***************************************************************************
+ *
+ * External parallel bus access
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Request ownership of the IB external parallel bus
+ *
+ * @v linda Linda device
+ * @ret rc Return status code
+ */
+static int linda_ib_epb_request ( struct linda *linda ) {
+ struct QIB_7220_ibsd_epb_access_ctrl access;
+ unsigned int i;
+
+ /* Request ownership */
+ memset ( &access, 0, sizeof ( access ) );
+ BIT_FILL_1 ( &access, sw_ib_epb_req, 1 );
+ linda_writeq ( linda, &access, QIB_7220_ibsd_epb_access_ctrl_offset );
+
+ /* Wait for ownership to be granted */
+ for ( i = 0 ; i < LINDA_EPB_REQUEST_MAX_WAIT_US ; i++ ) {
+ linda_readq ( linda, &access,
+ QIB_7220_ibsd_epb_access_ctrl_offset );
+ if ( BIT_GET ( &access, sw_ib_epb_req_granted ) )
+ return 0;
+ udelay ( 1 );
+ }
+
+ DBGC ( linda, "Linda %p timed out waiting for IB EPB request\n",
+ linda );
+ return -ETIMEDOUT;
+}
+
+/**
+ * Wait for IB external parallel bus transaction to complete
+ *
+ * @v linda Linda device
+ * @v xact Buffer to hold transaction result
+ * @ret rc Return status code
+ */
+static int linda_ib_epb_wait ( struct linda *linda,
+ struct QIB_7220_ibsd_epb_transaction_reg *xact ) {
+ unsigned int i;
+
+ /* Discard first read to allow for signals crossing clock domains */
+ linda_readq ( linda, xact, QIB_7220_ibsd_epb_transaction_reg_offset );
+
+ for ( i = 0 ; i < LINDA_EPB_XACT_MAX_WAIT_US ; i++ ) {
+ linda_readq ( linda, xact,
+ QIB_7220_ibsd_epb_transaction_reg_offset );
+ if ( BIT_GET ( xact, ib_epb_rdy ) ) {
+ if ( BIT_GET ( xact, ib_epb_req_error ) ) {
+ DBGC ( linda, "Linda %p EPB transaction "
+ "failed\n", linda );
+ return -EIO;
+ } else {
+ return 0;
+ }
+ }
+ udelay ( 1 );
+ }
+
+ DBGC ( linda, "Linda %p timed out waiting for IB EPB transaction\n",
+ linda );
+ return -ETIMEDOUT;
+}
+
+/**
+ * Release ownership of the IB external parallel bus
+ *
+ * @v linda Linda device
+ */
+static void linda_ib_epb_release ( struct linda *linda ) {
+ struct QIB_7220_ibsd_epb_access_ctrl access;
+
+ memset ( &access, 0, sizeof ( access ) );
+ BIT_FILL_1 ( &access, sw_ib_epb_req, 0 );
+ linda_writeq ( linda, &access, QIB_7220_ibsd_epb_access_ctrl_offset );
+}
+
+/**
+ * Read data via IB external parallel bus
+ *
+ * @v linda Linda device
+ * @v location EPB location
+ * @ret data Data read, or negative error
+ *
+ * You must have already acquired ownership of the IB external
+ * parallel bus.
+ */
+static int linda_ib_epb_read ( struct linda *linda, unsigned int location ) {
+ struct QIB_7220_ibsd_epb_transaction_reg xact;
+ unsigned int data;
+ int rc;
+
+ /* Ensure no transaction is currently in progress */
+ if ( ( rc = linda_ib_epb_wait ( linda, &xact ) ) != 0 )
+ return rc;
+
+ /* Process data */
+ memset ( &xact, 0, sizeof ( xact ) );
+ BIT_FILL_3 ( &xact,
+ ib_epb_address, LINDA_EPB_LOC_ADDRESS ( location ),
+ ib_epb_read_write, LINDA_EPB_READ,
+ ib_epb_cs, LINDA_EPB_LOC_CS ( location ) );
+ linda_writeq ( linda, &xact,
+ QIB_7220_ibsd_epb_transaction_reg_offset );
+
+ /* Wait for transaction to complete */
+ if ( ( rc = linda_ib_epb_wait ( linda, &xact ) ) != 0 )
+ return rc;
+
+ data = BIT_GET ( &xact, ib_epb_data );
+ return data;
+}
+
+/**
+ * Write data via IB external parallel bus
+ *
+ * @v linda Linda device
+ * @v location EPB location
+ * @v data Data to write
+ * @ret rc Return status code
+ *
+ * You must have already acquired ownership of the IB external
+ * parallel bus.
+ */
+static int linda_ib_epb_write ( struct linda *linda, unsigned int location,
+ unsigned int data ) {
+ struct QIB_7220_ibsd_epb_transaction_reg xact;
+ int rc;
+
+ /* Ensure no transaction is currently in progress */
+ if ( ( rc = linda_ib_epb_wait ( linda, &xact ) ) != 0 )
+ return rc;
+
+ /* Process data */
+ memset ( &xact, 0, sizeof ( xact ) );
+ BIT_FILL_4 ( &xact,
+ ib_epb_data, data,
+ ib_epb_address, LINDA_EPB_LOC_ADDRESS ( location ),
+ ib_epb_read_write, LINDA_EPB_WRITE,
+ ib_epb_cs, LINDA_EPB_LOC_CS ( location ) );
+ linda_writeq ( linda, &xact,
+ QIB_7220_ibsd_epb_transaction_reg_offset );
+
+ /* Wait for transaction to complete */
+ if ( ( rc = linda_ib_epb_wait ( linda, &xact ) ) != 0 )
+ return rc;
+
+ return 0;
+}
+
+/**
+ * Read/modify/write EPB register
+ *
+ * @v linda Linda device
+ * @v cs Chip select
+ * @v channel Channel
+ * @v element Element
+ * @v reg Register
+ * @v value Value to set
+ * @v mask Mask to apply to old value
+ * @ret rc Return status code
+ */
+static int linda_ib_epb_mod_reg ( struct linda *linda, unsigned int cs,
+ unsigned int channel, unsigned int element,
+ unsigned int reg, unsigned int value,
+ unsigned int mask ) {
+ unsigned int location;
+ int old_value;
+ int rc;
+
+ DBG_DISABLE ( DBGLVL_IO );
+
+ /* Sanity check */
+ assert ( ( value & mask ) == value );
+
+ /* Acquire bus ownership */
+ if ( ( rc = linda_ib_epb_request ( linda ) ) != 0 )
+ goto out;
+
+ /* Read existing value, if necessary */
+ location = LINDA_EPB_LOC ( cs, channel, element, reg );
+ if ( (~mask) & 0xff ) {
+ old_value = linda_ib_epb_read ( linda, location );
+ if ( old_value < 0 ) {
+ rc = old_value;
+ goto out_release;
+ }
+ } else {
+ old_value = 0;
+ }
+
+ /* Update value */
+ value = ( ( old_value & ~mask ) | value );
+ DBGCP ( linda, "Linda %p CS %d EPB(%d,%d,%#02x) %#02x => %#02x\n",
+ linda, cs, channel, element, reg, old_value, value );
+ if ( ( rc = linda_ib_epb_write ( linda, location, value ) ) != 0 )
+ goto out_release;
+
+ out_release:
+ /* Release bus */
+ linda_ib_epb_release ( linda );
+ out:
+ DBG_ENABLE ( DBGLVL_IO );
+ return rc;
+}
+
+/**
+ * Transfer data to/from microcontroller RAM
+ *
+ * @v linda Linda device
+ * @v address Starting address
+ * @v write Data to write, or NULL
+ * @v read Data to read, or NULL
+ * @v len Length of data
+ * @ret rc Return status code
+ */
+static int linda_ib_epb_ram_xfer ( struct linda *linda, unsigned int address,
+ const void *write, void *read,
+ size_t len ) {
+ unsigned int control;
+ unsigned int address_hi;
+ unsigned int address_lo;
+ int data;
+ int rc;
+
+ DBG_DISABLE ( DBGLVL_IO );
+
+ assert ( ! ( write && read ) );
+ assert ( ( address % LINDA_EPB_UC_CHUNK_SIZE ) == 0 );
+ assert ( ( len % LINDA_EPB_UC_CHUNK_SIZE ) == 0 );
+
+ /* Acquire bus ownership */
+ if ( ( rc = linda_ib_epb_request ( linda ) ) != 0 )
+ goto out;
+
+ /* Process data */
+ while ( len ) {
+
+ /* Reset the address for each new chunk */
+ if ( ( address % LINDA_EPB_UC_CHUNK_SIZE ) == 0 ) {
+
+ /* Write the control register */
+ control = ( read ? LINDA_EPB_UC_CTL_READ :
+ LINDA_EPB_UC_CTL_WRITE );
+ if ( ( rc = linda_ib_epb_write ( linda,
+ LINDA_EPB_UC_CTL,
+ control ) ) != 0 )
+ break;
+
+ /* Write the address registers */
+ address_hi = ( address >> 8 );
+ if ( ( rc = linda_ib_epb_write ( linda,
+ LINDA_EPB_UC_ADDR_HI,
+ address_hi ) ) != 0 )
+ break;
+ address_lo = ( address & 0xff );
+ if ( ( rc = linda_ib_epb_write ( linda,
+ LINDA_EPB_UC_ADDR_LO,
+ address_lo ) ) != 0 )
+ break;
+ }
+
+ /* Read or write the data */
+ if ( read ) {
+ data = linda_ib_epb_read ( linda, LINDA_EPB_UC_DATA );
+ if ( data < 0 ) {
+ rc = data;
+ break;
+ }
+ *( ( uint8_t * ) read++ ) = data;
+ } else {
+ data = *( ( uint8_t * ) write++ );
+ if ( ( rc = linda_ib_epb_write ( linda,
+ LINDA_EPB_UC_DATA,
+ data ) ) != 0 )
+ break;
+ }
+ address++;
+ len--;
+
+ /* Reset the control byte after each chunk */
+ if ( ( address % LINDA_EPB_UC_CHUNK_SIZE ) == 0 ) {
+ if ( ( rc = linda_ib_epb_write ( linda,
+ LINDA_EPB_UC_CTL,
+ 0 ) ) != 0 )
+ break;
+ }
+ }
+
+ /* Release bus */
+ linda_ib_epb_release ( linda );
+
+ out:
+ DBG_ENABLE ( DBGLVL_IO );
+ return rc;
+}
+
+/***************************************************************************
+ *
+ * Infiniband SerDes initialisation
+ *
+ ***************************************************************************
+ */
+
+/** A Linda SerDes parameter */
+struct linda_serdes_param {
+ /** EPB address as constructed by LINDA_EPB_ADDRESS() */
+ uint16_t address;
+ /** Value to set */
+ uint8_t value;
+ /** Mask to apply to old value */
+ uint8_t mask;
+} __packed;
+
+/** Magic "all channels" channel number */
+#define LINDA_EPB_ALL_CHANNELS 31
+
+/** End of SerDes parameter list marker */
+#define LINDA_SERDES_PARAM_END { 0, 0, 0 }
+
+/**
+ * Program IB SerDes register(s)
+ *
+ * @v linda Linda device
+ * @v param SerDes parameter
+ * @ret rc Return status code
+ */
+static int linda_set_serdes_param ( struct linda *linda,
+ struct linda_serdes_param *param ) {
+ unsigned int channel;
+ unsigned int channel_start;
+ unsigned int channel_end;
+ unsigned int element;
+ unsigned int reg;
+ int rc;
+
+ /* Break down the EPB address and determine channels */
+ channel = LINDA_EPB_ADDRESS_CHANNEL ( param->address );
+ element = LINDA_EPB_ADDRESS_ELEMENT ( param->address );
+ reg = LINDA_EPB_ADDRESS_REG ( param->address );
+ if ( channel == LINDA_EPB_ALL_CHANNELS ) {
+ channel_start = 0;
+ channel_end = 3;
+ } else {
+ channel_start = channel_end = channel;
+ }
+
+ /* Modify register for each specified channel */
+ for ( channel = channel_start ; channel <= channel_end ; channel++ ) {
+ if ( ( rc = linda_ib_epb_mod_reg ( linda, LINDA_EPB_CS_SERDES,
+ channel, element, reg,
+ param->value,
+ param->mask ) ) != 0 )
+ return rc;
+ }
+
+ return 0;
+}
+
+/**
+ * Program IB SerDes registers
+ *
+ * @v linda Linda device
+ * @v param SerDes parameters
+ * @v count Number of parameters
+ * @ret rc Return status code
+ */
+static int linda_set_serdes_params ( struct linda *linda,
+ struct linda_serdes_param *params ) {
+ int rc;
+
+ for ( ; params->mask != 0 ; params++ ){
+ if ( ( rc = linda_set_serdes_param ( linda,
+ params ) ) != 0 )
+ return rc;
+ }
+
+ return 0;
+}
+
+#define LINDA_DDS_VAL( amp_d, main_d, ipst_d, ipre_d, \
+ amp_s, main_s, ipst_s, ipre_s ) \
+ { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 9, 0x00 ), \
+ ( ( ( amp_d & 0x1f ) << 1 ) | 1 ), 0xff }, \
+ { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 9, 0x01 ), \
+ ( ( ( amp_s & 0x1f ) << 1 ) | 1 ), 0xff }, \
+ { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 9, 0x09 ), \
+ ( ( main_d << 3 ) | 4 | ( ipre_d >> 2 ) ), 0xff }, \
+ { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 9, 0x0a ), \
+ ( ( main_s << 3 ) | 4 | ( ipre_s >> 2 ) ), 0xff }, \
+ { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 9, 0x06 ), \
+ ( ( ( ipst_d & 0xf ) << 1 ) | \
+ ( ( ipre_d & 3 ) << 6 ) | 0x21 ), 0xff }, \
+ { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 9, 0x07 ), \
+ ( ( ( ipst_s & 0xf ) << 1 ) | \
+ ( ( ipre_s & 3 ) << 6) | 0x21 ), 0xff }
+
+/**
+ * Linda SerDes default parameters
+ *
+ * These magic start-of-day values are taken from the Linux driver.
+ */
+static struct linda_serdes_param linda_serdes_defaults1[] = {
+ /* RXHSCTRL0 */
+ { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 6, 0x00 ), 0xd4, 0xff },
+ /* VCDL_DAC2 */
+ { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 6, 0x05 ), 0x2d, 0xff },
+ /* VCDL_CTRL2 */
+ { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 6, 0x08 ), 0x03, 0x0f },
+ /* START_EQ1 */
+ { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 7, 0x27 ), 0x10, 0xff },
+ /* START_EQ2 */
+ { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 7, 0x28 ), 0x30, 0xff },
+ /* BACTRL */
+ { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 6, 0x0e ), 0x40, 0xff },
+ /* LDOUTCTRL1 */
+ { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 7, 0x06 ), 0x04, 0xff },
+ /* RXHSSTATUS */
+ { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 6, 0x0f ), 0x04, 0xff },
+ /* End of this block */
+ LINDA_SERDES_PARAM_END
+};
+static struct linda_serdes_param linda_serdes_defaults2[] = {
+ /* LDOUTCTRL1 */
+ { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 7, 0x06 ), 0x00, 0xff },
+ /* DDS values */
+ LINDA_DDS_VAL ( 31, 19, 12, 0, 29, 22, 9, 0 ),
+ /* Set Rcv Eq. to Preset node */
+ { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 7, 0x27 ), 0x10, 0xff },
+ /* DFELTHFDR */
+ { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 7, 0x08 ), 0x00, 0xff },
+ /* DFELTHHDR */
+ { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 7, 0x21 ), 0x00, 0xff },
+ /* TLTHFDR */
+ { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 7, 0x09 ), 0x02, 0xff },
+ /* TLTHHDR */
+ { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 7, 0x23 ), 0x02, 0xff },
+ /* ZFR */
+ { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 7, 0x1b ), 0x0c, 0xff },
+ /* ZCNT) */
+ { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 7, 0x1c ), 0x0c, 0xff },
+ /* GFR */
+ { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 7, 0x1e ), 0x10, 0xff },
+ /* GHR */
+ { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 7, 0x1f ), 0x10, 0xff },
+ /* VCDL_CTRL0 toggle */
+ { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 6, 0x06 ), 0x20, 0xff },
+ { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 6, 0x06 ), 0x00, 0xff },
+ /* CMUCTRL5 */
+ { LINDA_EPB_ADDRESS ( 7, 0, 0x15 ), 0x80, 0xff },
+ /* End of this block */
+ LINDA_SERDES_PARAM_END
+};
+static struct linda_serdes_param linda_serdes_defaults3[] = {
+ /* START_EQ1 */
+ { LINDA_EPB_ADDRESS ( LINDA_EPB_ALL_CHANNELS, 7, 0x27 ), 0x00, 0x38 },
+ /* End of this block */
+ LINDA_SERDES_PARAM_END
+};
+
+/**
+ * Program the microcontroller RAM
+ *
+ * @v linda Linda device
+ * @ret rc Return status code
+ */
+static int linda_program_uc_ram ( struct linda *linda ) {
+ int rc;
+
+ if ( ( rc = linda_ib_epb_ram_xfer ( linda, 0, linda_ib_fw, NULL,
+ sizeof ( linda_ib_fw ) ) ) != 0 ){
+ DBGC ( linda, "Linda %p could not load IB firmware: %s\n",
+ linda, strerror ( rc ) );
+ return rc;
+ }
+
+ return 0;
+}
+
+/**
+ * Verify the microcontroller RAM
+ *
+ * @v linda Linda device
+ * @ret rc Return status code
+ */
+static int linda_verify_uc_ram ( struct linda *linda ) {
+ uint8_t verify[LINDA_EPB_UC_CHUNK_SIZE];
+ unsigned int offset;
+ int rc;
+
+ for ( offset = 0 ; offset < sizeof ( linda_ib_fw );
+ offset += sizeof ( verify ) ) {
+ if ( ( rc = linda_ib_epb_ram_xfer ( linda, offset,
+ NULL, verify,
+ sizeof (verify) )) != 0 ){
+ DBGC ( linda, "Linda %p could not read back IB "
+ "firmware: %s\n", linda, strerror ( rc ) );
+ return rc;
+ }
+ if ( memcmp ( ( linda_ib_fw + offset ), verify,
+ sizeof ( verify ) ) != 0 ) {
+ DBGC ( linda, "Linda %p firmware verification failed "
+ "at offset %#x\n", linda, offset );
+ DBGC_HDA ( linda, offset, ( linda_ib_fw + offset ),
+ sizeof ( verify ) );
+ DBGC_HDA ( linda, offset, verify, sizeof ( verify ) );
+ return -EIO;
+ }
+ }
+
+ DBGC2 ( linda, "Linda %p firmware verified ok\n", linda );
+ return 0;
+}
+
+/**
+ * Use the microcontroller to trim the IB link
+ *
+ * @v linda Linda device
+ * @ret rc Return status code
+ */
+static int linda_trim_ib ( struct linda *linda ) {
+ struct QIB_7220_IBSerDesCtrl ctrl;
+ struct QIB_7220_IntStatus intstatus;
+ unsigned int i;
+ int rc;
+
+ /* Bring the microcontroller out of reset */
+ linda_readq ( linda, &ctrl, QIB_7220_IBSerDesCtrl_offset );
+ BIT_SET ( &ctrl, ResetIB_uC_Core, 0 );
+ linda_writeq ( linda, &ctrl, QIB_7220_IBSerDesCtrl_offset );
+
+ /* Wait for the "trim done" signal */
+ for ( i = 0 ; i < LINDA_TRIM_DONE_MAX_WAIT_MS ; i++ ) {
+ linda_readq ( linda, &intstatus, QIB_7220_IntStatus_offset );
+ if ( BIT_GET ( &intstatus, IBSerdesTrimDone ) ) {
+ rc = 0;
+ goto out_reset;
+ }
+ mdelay ( 1 );
+ }
+
+ DBGC ( linda, "Linda %p timed out waiting for trim done\n", linda );
+ rc = -ETIMEDOUT;
+ out_reset:
+ /* Put the microcontroller back into reset */
+ BIT_SET ( &ctrl, ResetIB_uC_Core, 1 );
+ linda_writeq ( linda, &ctrl, QIB_7220_IBSerDesCtrl_offset );
+
+ return rc;
+}
+
+/**
+ * Initialise the IB SerDes
+ *
+ * @v linda Linda device
+ * @ret rc Return status code
+ */
+static int linda_init_ib_serdes ( struct linda *linda ) {
+ struct QIB_7220_Control control;
+ struct QIB_7220_IBCCtrl ibcctrl;
+ struct QIB_7220_IBCDDRCtrl ibcddrctrl;
+ struct QIB_7220_XGXSCfg xgxscfg;
+ int rc;
+
+ /* Disable link */
+ linda_readq ( linda, &control, QIB_7220_Control_offset );
+ BIT_SET ( &control, LinkEn, 0 );
+ linda_writeq ( linda, &control, QIB_7220_Control_offset );
+
+ /* Configure sensible defaults for IBC */
+ memset ( &ibcctrl, 0, sizeof ( ibcctrl ) );
+ BIT_FILL_6 ( &ibcctrl, /* Tuning values taken from Linux driver */
+ FlowCtrlPeriod, 0x03,
+ FlowCtrlWaterMark, 0x05,
+ MaxPktLen, ( ( LINDA_RECV_HEADER_SIZE +
+ LINDA_RECV_PAYLOAD_SIZE +
+ 4 /* ICRC */ ) >> 2 ),
+ PhyerrThreshold, 0xf,
+ OverrunThreshold, 0xf,
+ CreditScale, 0x4 );
+ linda_writeq ( linda, &ibcctrl, QIB_7220_IBCCtrl_offset );
+
+ /* Force SDR only to avoid needing all the DDR tuning,
+ * Mellanox compatibiltiy hacks etc. SDR is plenty for
+ * boot-time operation.
+ */
+ linda_readq ( linda, &ibcddrctrl, QIB_7220_IBCDDRCtrl_offset );
+ BIT_SET ( &ibcddrctrl, IB_ENHANCED_MODE, 0 );
+ BIT_SET ( &ibcddrctrl, SD_SPEED_SDR, 1 );
+ BIT_SET ( &ibcddrctrl, SD_SPEED_DDR, 0 );
+ BIT_SET ( &ibcddrctrl, SD_SPEED_QDR, 0 );
+ BIT_SET ( &ibcddrctrl, HRTBT_ENB, 0 );
+ BIT_SET ( &ibcddrctrl, HRTBT_AUTO, 0 );
+ linda_writeq ( linda, &ibcddrctrl, QIB_7220_IBCDDRCtrl_offset );
+
+ /* Set default SerDes parameters */
+ if ( ( rc = linda_set_serdes_params ( linda,
+ linda_serdes_defaults1 ) ) != 0 )
+ return rc;
+ udelay ( 415 ); /* Magic delay while SerDes sorts itself out */
+ if ( ( rc = linda_set_serdes_params ( linda,
+ linda_serdes_defaults2 ) ) != 0 )
+ return rc;
+
+ /* Program the microcontroller RAM */
+ if ( ( rc = linda_program_uc_ram ( linda ) ) != 0 )
+ return rc;
+
+ /* Verify the microcontroller RAM contents */
+ if ( DBGLVL_LOG ) {
+ if ( ( rc = linda_verify_uc_ram ( linda ) ) != 0 )
+ return rc;
+ }
+
+ /* More SerDes tuning */
+ if ( ( rc = linda_set_serdes_params ( linda,
+ linda_serdes_defaults3 ) ) != 0 )
+ return rc;
+
+ /* Use the microcontroller to trim the IB link */
+ if ( ( rc = linda_trim_ib ( linda ) ) != 0 )
+ return rc;
+
+ /* Bring XGXS out of reset */
+ linda_readq ( linda, &xgxscfg, QIB_7220_XGXSCfg_offset );
+ BIT_SET ( &xgxscfg, tx_rx_reset, 0 );
+ BIT_SET ( &xgxscfg, xcv_reset, 0 );
+ linda_writeq ( linda, &xgxscfg, QIB_7220_XGXSCfg_offset );
+
+ return rc;
+}
+
+/***************************************************************************
+ *
+ * PCI layer interface
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Probe PCI device
+ *
+ * @v pci PCI device
+ * @v id PCI ID
+ * @ret rc Return status code
+ */
+static int linda_probe ( struct pci_device *pci,
+ const struct pci_device_id *id __unused ) {
+ struct ib_device *ibdev;
+ struct linda *linda;
+ struct QIB_7220_Revision revision;
+ int rc;
+
+ /* Allocate Infiniband device */
+ ibdev = alloc_ibdev ( sizeof ( *linda ) );
+ if ( ! ibdev ) {
+ rc = -ENOMEM;
+ goto err_alloc_ibdev;
+ }
+ pci_set_drvdata ( pci, ibdev );
+ linda = ib_get_drvdata ( ibdev );
+ ibdev->op = &linda_ib_operations;
+ ibdev->dev = &pci->dev;
+ ibdev->port = 1;
+
+ /* Fix up PCI device */
+ adjust_pci_device ( pci );
+
+ /* Get PCI BARs */
+ linda->regs = ioremap ( pci->membase, LINDA_BAR0_SIZE );
+ DBGC2 ( linda, "Linda %p has BAR at %08lx\n", linda, pci->membase );
+
+ /* Print some general data */
+ linda_readq ( linda, &revision, QIB_7220_Revision_offset );
+ DBGC2 ( linda, "Linda %p board %02lx v%ld.%ld.%ld.%ld\n", linda,
+ BIT_GET ( &revision, BoardID ),
+ BIT_GET ( &revision, R_SW ),
+ BIT_GET ( &revision, R_Arch ),
+ BIT_GET ( &revision, R_ChipRevMajor ),
+ BIT_GET ( &revision, R_ChipRevMinor ) );
+
+ /* Initialise I2C subsystem */
+ if ( ( rc = linda_init_i2c ( linda ) ) != 0 )
+ goto err_init_i2c;
+
+ /* Read EEPROM parameters */
+ if ( ( rc = linda_read_eeprom ( linda, &ibdev->gid.u.half[1] ) ) != 0 )
+ goto err_read_eeprom;
+
+ /* Initialise send datapath */
+ if ( ( rc = linda_init_send ( linda ) ) != 0 )
+ goto err_init_send;
+
+ /* Initialise receive datapath */
+ if ( ( rc = linda_init_recv ( linda ) ) != 0 )
+ goto err_init_recv;
+
+ /* Initialise the IB SerDes */
+ if ( ( rc = linda_init_ib_serdes ( linda ) ) != 0 )
+ goto err_init_ib_serdes;
+
+ /* Create the SMA */
+ if ( ( rc = ib_create_sma ( &linda->sma, ibdev,
+ &linda_sma_operations ) ) != 0 )
+ goto err_create_sma;
+ /* If the SMA doesn't get context 0, we're screwed */
+ assert ( linda_qpn_to_ctx ( linda->sma.qp->qpn ) == 0 );
+
+ /* Register Infiniband device */
+ if ( ( rc = register_ibdev ( ibdev ) ) != 0 ) {
+ DBGC ( linda, "Linda %p could not register IB "
+ "device: %s\n", linda, strerror ( rc ) );
+ goto err_register_ibdev;
+ }
+
+ return 0;
+
+ unregister_ibdev ( ibdev );
+ err_register_ibdev:
+ ib_destroy_sma ( &linda->sma );
+ err_create_sma:
+ linda_fini_recv ( linda );
+ err_init_recv:
+ linda_fini_send ( linda );
+ err_init_send:
+ err_init_ib_serdes:
+ err_read_eeprom:
+ err_init_i2c:
+ ibdev_put ( ibdev );
+ err_alloc_ibdev:
+ return rc;
+}
+
+/**
+ * Remove PCI device
+ *
+ * @v pci PCI device
+ */
+static void linda_remove ( struct pci_device *pci ) {
+ struct ib_device *ibdev = pci_get_drvdata ( pci );
+ struct linda *linda = ib_get_drvdata ( ibdev );
+
+ unregister_ibdev ( ibdev );
+ ib_destroy_sma ( &linda->sma );
+ linda_fini_recv ( linda );
+ linda_fini_send ( linda );
+ ibdev_put ( ibdev );
+}
+
+static struct pci_device_id linda_nics[] = {
+ PCI_ROM ( 0x1077, 0x7220, "iba7220", "QLE7240/7280 HCA driver" ),
+};
+
+struct pci_driver linda_driver __pci_driver = {
+ .ids = linda_nics,
+ .id_count = ( sizeof ( linda_nics ) / sizeof ( linda_nics[0] ) ),
+ .probe = linda_probe,
+ .remove = linda_remove,
+};
diff --git a/gpxe/src/drivers/infiniband/linda.h b/gpxe/src/drivers/infiniband/linda.h
new file mode 100644
index 00000000..dd1737a6
--- /dev/null
+++ b/gpxe/src/drivers/infiniband/linda.h
@@ -0,0 +1,271 @@
+#ifndef _LINDA_H
+#define _LINDA_H
+
+/*
+ * Copyright (C) 2008 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.
+ */
+
+/**
+ * @file
+ *
+ * QLogic Linda Infiniband HCA
+ *
+ */
+
+#define BITOPS_LITTLE_ENDIAN
+#include <gpxe/bitops.h>
+#include "qib_7220_regs.h"
+
+struct ib_device;
+
+/** A Linda GPIO register */
+struct QIB_7220_GPIO_pb {
+ pseudo_bit_t GPIO[16];
+ pseudo_bit_t Reserved[48];
+};
+struct QIB_7220_GPIO {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_GPIO_pb );
+};
+
+/** A Linda general scalar register */
+struct QIB_7220_scalar_pb {
+ pseudo_bit_t Value[64];
+};
+struct QIB_7220_scalar {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_scalar_pb );
+};
+
+/** Linda send per-buffer control word */
+struct QIB_7220_SendPbc_pb {
+ pseudo_bit_t LengthP1_toibc[11];
+ pseudo_bit_t Reserved1[4];
+ pseudo_bit_t LengthP1_trigger[11];
+ pseudo_bit_t Reserved2[3];
+ pseudo_bit_t TestEbp[1];
+ pseudo_bit_t Test[1];
+ pseudo_bit_t Intr[1];
+ pseudo_bit_t Reserved3[31];
+ pseudo_bit_t VL15[1];
+};
+struct QIB_7220_SendPbc {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_SendPbc_pb );
+};
+
+/** Linda send buffer availability */
+struct QIB_7220_SendBufAvail_pb {
+ pseudo_bit_t InUseCheck[144][2];
+ pseudo_bit_t Reserved[32];
+};
+struct QIB_7220_SendBufAvail {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_SendBufAvail_pb );
+};
+
+/** DMA alignment for send buffer availability */
+#define LINDA_SENDBUFAVAIL_ALIGN 64
+
+/** A Linda eager receive descriptor */
+struct QIB_7220_RcvEgr_pb {
+ pseudo_bit_t Addr[37];
+ pseudo_bit_t BufSize[3];
+ pseudo_bit_t Reserved[24];
+};
+struct QIB_7220_RcvEgr {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvEgr_pb );
+};
+
+/** Linda receive header flags */
+struct QIB_7220_RcvHdrFlags_pb {
+ pseudo_bit_t PktLen[11];
+ pseudo_bit_t RcvType[3];
+ pseudo_bit_t SoftB[1];
+ pseudo_bit_t SoftA[1];
+ pseudo_bit_t EgrIndex[12];
+ pseudo_bit_t Reserved1[3];
+ pseudo_bit_t UseEgrBfr[1];
+ pseudo_bit_t RcvSeq[4];
+ pseudo_bit_t HdrqOffset[11];
+ pseudo_bit_t Reserved2[8];
+ pseudo_bit_t IBErr[1];
+ pseudo_bit_t MKErr[1];
+ pseudo_bit_t TIDErr[1];
+ pseudo_bit_t KHdrErr[1];
+ pseudo_bit_t MTUErr[1];
+ pseudo_bit_t LenErr[1];
+ pseudo_bit_t ParityErr[1];
+ pseudo_bit_t VCRCErr[1];
+ pseudo_bit_t ICRCErr[1];
+};
+struct QIB_7220_RcvHdrFlags {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrFlags_pb );
+};
+
+/** Linda memory BAR size */
+#define LINDA_BAR0_SIZE 0x400000
+
+/** Linda I2C SCL line GPIO number */
+#define LINDA_GPIO_SCL 0
+
+/** Linda I2C SDA line GPIO number */
+#define LINDA_GPIO_SDA 1
+
+/** GUID offset within EEPROM */
+#define LINDA_EEPROM_GUID_OFFSET 3
+
+/** GUID size within EEPROM */
+#define LINDA_EEPROM_GUID_SIZE 8
+
+/** Board serial number offset within EEPROM */
+#define LINDA_EEPROM_SERIAL_OFFSET 12
+
+/** Board serial number size within EEPROM */
+#define LINDA_EEPROM_SERIAL_SIZE 12
+
+/** Maximum number of send buffers used
+ *
+ * This is a policy decision. Must be less than or equal to the total
+ * number of send buffers supported by the hardware (128).
+ */
+#define LINDA_MAX_SEND_BUFS 32
+
+/** Linda send buffer size */
+#define LINDA_SEND_BUF_SIZE 4096
+
+/** Number of contexts (including kernel context)
+ *
+ * This is a policy decision. Must be 5, 9 or 17.
+ */
+#define LINDA_NUM_CONTEXTS 5
+
+/** PortCfg values for different numbers of contexts */
+enum linda_portcfg {
+ LINDA_PORTCFG_5CTX = 0,
+ LINDA_PORTCFG_9CTX = 1,
+ LINDA_PORTCFG_17CTX = 2,
+};
+
+/** PortCfg values for different numbers of contexts */
+#define LINDA_EAGER_ARRAY_SIZE_5CTX_0 2048
+#define LINDA_EAGER_ARRAY_SIZE_5CTX_OTHER 4096
+#define LINDA_EAGER_ARRAY_SIZE_9CTX_0 2048
+#define LINDA_EAGER_ARRAY_SIZE_9CTX_OTHER 2048
+#define LINDA_EAGER_ARRAY_SIZE_17CTX_0 2048
+#define LINDA_EAGER_ARRAY_SIZE_17CTX_OTHER 1024
+
+/** Eager buffer required alignment */
+#define LINDA_EAGER_BUFFER_ALIGN 2048
+
+/** Eager buffer size encodings */
+enum linda_eager_buffer_size {
+ LINDA_EAGER_BUFFER_NONE = 0,
+ LINDA_EAGER_BUFFER_2K = 1,
+ LINDA_EAGER_BUFFER_4K = 2,
+ LINDA_EAGER_BUFFER_8K = 3,
+ LINDA_EAGER_BUFFER_16K = 4,
+ LINDA_EAGER_BUFFER_32K = 5,
+ LINDA_EAGER_BUFFER_64K = 6,
+};
+
+/** Number of RX headers per context
+ *
+ * This is a policy decision.
+ */
+#define LINDA_RECV_HEADER_COUNT 8
+
+/** Maximum size of each RX header
+ *
+ * This is a policy decision. Must be divisible by 4.
+ */
+#define LINDA_RECV_HEADER_SIZE 96
+
+/** Total size of an RX header ring */
+#define LINDA_RECV_HEADERS_SIZE \
+ ( LINDA_RECV_HEADER_SIZE * LINDA_RECV_HEADER_COUNT )
+
+/** RX header alignment */
+#define LINDA_RECV_HEADERS_ALIGN 64
+
+/** RX payload size
+ *
+ * This is a policy decision. Must be a valid eager buffer size.
+ */
+#define LINDA_RECV_PAYLOAD_SIZE 2048
+
+/** QPN used for Infinipath Packets
+ *
+ * This is a policy decision. Must have bit 0 clear. Must not be a
+ * QPN that we will use.
+ */
+#define LINDA_QP_IDETH 0xdead0
+
+/** Maximum time for wait for external parallel bus request, in us */
+#define LINDA_EPB_REQUEST_MAX_WAIT_US 500
+
+/** Maximum time for wait for external parallel bus transaction, in us */
+#define LINDA_EPB_XACT_MAX_WAIT_US 500
+
+/** Linda external parallel bus chip selects */
+#define LINDA_EPB_CS_SERDES 1
+#define LINDA_EPB_CS_UC 2
+
+/** Linda external parallel bus read/write operations */
+#define LINDA_EPB_WRITE 0
+#define LINDA_EPB_READ 1
+
+/** Linda external parallel bus register addresses */
+#define LINDA_EPB_ADDRESS( _channel, _element, _reg ) \
+ ( (_element) | ( (_channel) << 4 ) | ( (_reg) << 9 ) )
+#define LINDA_EPB_ADDRESS_CHANNEL( _address ) ( ( (_address) >> 4 ) & 0x1f )
+#define LINDA_EPB_ADDRESS_ELEMENT( _address ) ( ( (_address) >> 0 ) & 0x0f )
+#define LINDA_EPB_ADDRESS_REG( _address ) ( ( (_address) >> 9 ) & 0x3f )
+
+/** Linda external parallel bus locations
+ *
+ * The location is used by the driver to encode both the chip select
+ * and the EPB address.
+ */
+#define LINDA_EPB_LOC( _cs, _channel, _element, _reg) \
+ ( ( (_cs) << 16 ) | LINDA_EPB_ADDRESS ( _channel, _element, _reg ) )
+#define LINDA_EPB_LOC_ADDRESS( _loc ) ( (_loc) & 0xffff )
+#define LINDA_EPB_LOC_CS( _loc ) ( (_loc) >> 16 )
+
+/** Linda external parallel bus microcontroller register addresses */
+#define LINDA_EPB_UC_CHANNEL 6
+#define LINDA_EPB_UC_LOC( _reg ) \
+ LINDA_EPB_LOC ( LINDA_EPB_CS_UC, LINDA_EPB_UC_CHANNEL, 0, (_reg) )
+#define LINDA_EPB_UC_CTL LINDA_EPB_UC_LOC ( 0 )
+#define LINDA_EPB_UC_CTL_WRITE 1
+#define LINDA_EPB_UC_CTL_READ 2
+#define LINDA_EPB_UC_ADDR_LO LINDA_EPB_UC_LOC ( 2 )
+#define LINDA_EPB_UC_ADDR_HI LINDA_EPB_UC_LOC ( 3 )
+#define LINDA_EPB_UC_DATA LINDA_EPB_UC_LOC ( 4 )
+#define LINDA_EPB_UC_CHUNK_SIZE 64
+
+extern uint8_t linda_ib_fw[8192];
+
+/** Maximum time to wait for "trim done" signal, in ms */
+#define LINDA_TRIM_DONE_MAX_WAIT_MS 1000
+
+/** Linda link states */
+enum linda_link_state {
+ LINDA_LINK_STATE_DOWN = 0,
+ LINDA_LINK_STATE_INIT = 1,
+ LINDA_LINK_STATE_ARM = 2,
+ LINDA_LINK_STATE_ACTIVE = 3,
+ LINDA_LINK_STATE_ACT_DEFER = 4,
+};
+
+#endif /* _LINDA_H */
diff --git a/gpxe/src/drivers/infiniband/linda_fw.c b/gpxe/src/drivers/infiniband/linda_fw.c
new file mode 100644
index 00000000..fc5ea077
--- /dev/null
+++ b/gpxe/src/drivers/infiniband/linda_fw.c
@@ -0,0 +1,1067 @@
+/*
+ * Copyright (c) 2007, 2008 QLogic Corporation. All rights reserved.
+ *
+ * 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 from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - 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.
+ *
+ * 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.
+ */
+
+/*
+ * This file contains the memory image from the vendor, to be copied into
+ * the IB SERDES of the IBA7220 during initialization.
+ * The file also includes the two functions which use this image.
+ */
+
+#include <stdint.h>
+#include "linda.h"
+
+uint8_t linda_ib_fw[8192] = {
+/*0000*/0x02, 0x0A, 0x29, 0x02, 0x0A, 0x87, 0xE5, 0xE6,
+ 0x30, 0xE6, 0x04, 0x7F, 0x01, 0x80, 0x02, 0x7F,
+/*0010*/0x00, 0xE5, 0xE2, 0x30, 0xE4, 0x04, 0x7E, 0x01,
+ 0x80, 0x02, 0x7E, 0x00, 0xEE, 0x5F, 0x60, 0x08,
+/*0020*/0x53, 0xF9, 0xF7, 0xE4, 0xF5, 0xFE, 0x80, 0x08,
+ 0x7F, 0x0A, 0x12, 0x17, 0x31, 0x12, 0x0E, 0xA2,
+/*0030*/0x75, 0xFC, 0x08, 0xE4, 0xF5, 0xFD, 0xE5, 0xE7,
+ 0x20, 0xE7, 0x03, 0x43, 0xF9, 0x08, 0x22, 0x00,
+/*0040*/0x01, 0x20, 0x11, 0x00, 0x04, 0x20, 0x00, 0x75,
+ 0x51, 0x01, 0xE4, 0xF5, 0x52, 0xF5, 0x53, 0xF5,
+/*0050*/0x52, 0xF5, 0x7E, 0x7F, 0x04, 0x02, 0x04, 0x38,
+ 0xC2, 0x36, 0x05, 0x52, 0xE5, 0x52, 0xD3, 0x94,
+/*0060*/0x0C, 0x40, 0x05, 0x75, 0x52, 0x01, 0xD2, 0x36,
+ 0x90, 0x07, 0x0C, 0x74, 0x07, 0xF0, 0xA3, 0x74,
+/*0070*/0xFF, 0xF0, 0xE4, 0xF5, 0x0C, 0xA3, 0xF0, 0x90,
+ 0x07, 0x14, 0xF0, 0xA3, 0xF0, 0x75, 0x0B, 0x20,
+/*0080*/0xF5, 0x09, 0xE4, 0xF5, 0x08, 0xE5, 0x08, 0xD3,
+ 0x94, 0x30, 0x40, 0x03, 0x02, 0x04, 0x04, 0x12,
+/*0090*/0x00, 0x06, 0x15, 0x0B, 0xE5, 0x08, 0x70, 0x04,
+ 0x7F, 0x01, 0x80, 0x02, 0x7F, 0x00, 0xE5, 0x09,
+/*00A0*/0x70, 0x04, 0x7E, 0x01, 0x80, 0x02, 0x7E, 0x00,
+ 0xEE, 0x5F, 0x60, 0x05, 0x12, 0x18, 0x71, 0xD2,
+/*00B0*/0x35, 0x53, 0xE1, 0xF7, 0xE5, 0x08, 0x45, 0x09,
+ 0xFF, 0xE5, 0x0B, 0x25, 0xE0, 0x25, 0xE0, 0x24,
+/*00C0*/0x83, 0xF5, 0x82, 0xE4, 0x34, 0x07, 0xF5, 0x83,
+ 0xEF, 0xF0, 0x85, 0xE2, 0x20, 0xE5, 0x52, 0xD3,
+/*00D0*/0x94, 0x01, 0x40, 0x0D, 0x12, 0x19, 0xF3, 0xE0,
+ 0x54, 0xA0, 0x64, 0x40, 0x70, 0x03, 0x02, 0x03,
+/*00E0*/0xFB, 0x53, 0xF9, 0xF8, 0x90, 0x94, 0x70, 0xE4,
+ 0xF0, 0xE0, 0xF5, 0x10, 0xAF, 0x09, 0x12, 0x1E,
+/*00F0*/0xB3, 0xAF, 0x08, 0xEF, 0x44, 0x08, 0xF5, 0x82,
+ 0x75, 0x83, 0x80, 0xE0, 0xF5, 0x29, 0xEF, 0x44,
+/*0100*/0x07, 0x12, 0x1A, 0x3C, 0xF5, 0x22, 0x54, 0x40,
+ 0xD3, 0x94, 0x00, 0x40, 0x1E, 0xE5, 0x29, 0x54,
+/*0110*/0xF0, 0x70, 0x21, 0x12, 0x19, 0xF3, 0xE0, 0x44,
+ 0x80, 0xF0, 0xE5, 0x22, 0x54, 0x30, 0x65, 0x08,
+/*0120*/0x70, 0x09, 0x12, 0x19, 0xF3, 0xE0, 0x54, 0xBF,
+ 0xF0, 0x80, 0x09, 0x12, 0x19, 0xF3, 0x74, 0x40,
+/*0130*/0xF0, 0x02, 0x03, 0xFB, 0x12, 0x1A, 0x12, 0x75,
+ 0x83, 0xAE, 0x74, 0xFF, 0xF0, 0xAF, 0x08, 0x7E,
+/*0140*/0x00, 0xEF, 0x44, 0x07, 0xF5, 0x82, 0xE0, 0xFD,
+ 0xE5, 0x0B, 0x25, 0xE0, 0x25, 0xE0, 0x24, 0x81,
+/*0150*/0xF5, 0x82, 0xE4, 0x34, 0x07, 0xF5, 0x83, 0xED,
+ 0xF0, 0x90, 0x07, 0x0E, 0xE0, 0x04, 0xF0, 0xEF,
+/*0160*/0x44, 0x07, 0xF5, 0x82, 0x75, 0x83, 0x98, 0xE0,
+ 0xF5, 0x28, 0x12, 0x1A, 0x23, 0x40, 0x0C, 0x12,
+/*0170*/0x19, 0xF3, 0xE0, 0x44, 0x01, 0x12, 0x1A, 0x32,
+ 0x02, 0x03, 0xF6, 0xAF, 0x08, 0x7E, 0x00, 0x74,
+/*0180*/0x80, 0xCD, 0xEF, 0xCD, 0x8D, 0x82, 0xF5, 0x83,
+ 0xE0, 0x30, 0xE0, 0x0A, 0x12, 0x19, 0xF3, 0xE0,
+/*0190*/0x44, 0x20, 0xF0, 0x02, 0x03, 0xFB, 0x12, 0x19,
+ 0xF3, 0xE0, 0x54, 0xDF, 0xF0, 0xEE, 0x44, 0xAE,
+/*01A0*/0x12, 0x1A, 0x43, 0x30, 0xE4, 0x03, 0x02, 0x03,
+ 0xFB, 0x74, 0x9E, 0x12, 0x1A, 0x05, 0x20, 0xE0,
+/*01B0*/0x03, 0x02, 0x03, 0xFB, 0x8F, 0x82, 0x8E, 0x83,
+ 0xE0, 0x20, 0xE0, 0x03, 0x02, 0x03, 0xFB, 0x12,
+/*01C0*/0x19, 0xF3, 0xE0, 0x44, 0x10, 0xF0, 0xE5, 0xE3,
+ 0x20, 0xE7, 0x08, 0xE5, 0x08, 0x12, 0x1A, 0x3A,
+/*01D0*/0x44, 0x04, 0xF0, 0xAF, 0x08, 0x7E, 0x00, 0xEF,
+ 0x12, 0x1A, 0x3A, 0x20, 0xE2, 0x34, 0x12, 0x19,
+/*01E0*/0xF3, 0xE0, 0x44, 0x08, 0xF0, 0xE5, 0xE4, 0x30,
+ 0xE6, 0x04, 0x7D, 0x01, 0x80, 0x02, 0x7D, 0x00,
+/*01F0*/0xE5, 0x7E, 0xC3, 0x94, 0x04, 0x50, 0x04, 0x7C,
+ 0x01, 0x80, 0x02, 0x7C, 0x00, 0xEC, 0x4D, 0x60,
+/*0200*/0x05, 0xC2, 0x35, 0x02, 0x03, 0xFB, 0xEE, 0x44,
+ 0xD2, 0x12, 0x1A, 0x43, 0x44, 0x40, 0xF0, 0x02,
+/*0210*/0x03, 0xFB, 0x12, 0x19, 0xF3, 0xE0, 0x54, 0xF7,
+ 0xF0, 0x12, 0x1A, 0x12, 0x75, 0x83, 0xD2, 0xE0,
+/*0220*/0x54, 0xBF, 0xF0, 0x90, 0x07, 0x14, 0xE0, 0x04,
+ 0xF0, 0xE5, 0x7E, 0x70, 0x03, 0x75, 0x7E, 0x01,
+/*0230*/0xAF, 0x08, 0x7E, 0x00, 0x12, 0x1A, 0x23, 0x40,
+ 0x12, 0x12, 0x19, 0xF3, 0xE0, 0x44, 0x01, 0x12,
+/*0240*/0x19, 0xF2, 0xE0, 0x54, 0x02, 0x12, 0x1A, 0x32,
+ 0x02, 0x03, 0xFB, 0x12, 0x19, 0xF3, 0xE0, 0x44,
+/*0250*/0x02, 0x12, 0x19, 0xF2, 0xE0, 0x54, 0xFE, 0xF0,
+ 0xC2, 0x35, 0xEE, 0x44, 0x8A, 0x8F, 0x82, 0xF5,
+/*0260*/0x83, 0xE0, 0xF5, 0x17, 0x54, 0x8F, 0x44, 0x40,
+ 0xF0, 0x74, 0x90, 0xFC, 0xE5, 0x08, 0x44, 0x07,
+/*0270*/0xFD, 0xF5, 0x82, 0x8C, 0x83, 0xE0, 0x54, 0x3F,
+ 0x90, 0x07, 0x02, 0xF0, 0xE0, 0x54, 0xC0, 0x8D,
+/*0280*/0x82, 0x8C, 0x83, 0xF0, 0x74, 0x92, 0x12, 0x1A,
+ 0x05, 0x90, 0x07, 0x03, 0x12, 0x1A, 0x19, 0x74,
+/*0290*/0x82, 0x12, 0x1A, 0x05, 0x90, 0x07, 0x04, 0x12,
+ 0x1A, 0x19, 0x74, 0xB4, 0x12, 0x1A, 0x05, 0x90,
+/*02A0*/0x07, 0x05, 0x12, 0x1A, 0x19, 0x74, 0x94, 0xFE,
+ 0xE5, 0x08, 0x44, 0x06, 0x12, 0x1A, 0x0A, 0xF5,
+/*02B0*/0x10, 0x30, 0xE0, 0x04, 0xD2, 0x37, 0x80, 0x02,
+ 0xC2, 0x37, 0xE5, 0x10, 0x54, 0x7F, 0x8F, 0x82,
+/*02C0*/0x8E, 0x83, 0xF0, 0x30, 0x44, 0x30, 0x12, 0x1A,
+ 0x03, 0x54, 0x80, 0xD3, 0x94, 0x00, 0x40, 0x04,
+/*02D0*/0xD2, 0x39, 0x80, 0x02, 0xC2, 0x39, 0x8F, 0x82,
+ 0x8E, 0x83, 0xE0, 0x44, 0x80, 0xF0, 0x12, 0x1A,
+/*02E0*/0x03, 0x54, 0x40, 0xD3, 0x94, 0x00, 0x40, 0x04,
+ 0xD2, 0x3A, 0x80, 0x02, 0xC2, 0x3A, 0x8F, 0x82,
+/*02F0*/0x8E, 0x83, 0xE0, 0x44, 0x40, 0xF0, 0x74, 0x92,
+ 0xFE, 0xE5, 0x08, 0x44, 0x06, 0x12, 0x1A, 0x0A,
+/*0300*/0x30, 0xE7, 0x04, 0xD2, 0x38, 0x80, 0x02, 0xC2,
+ 0x38, 0x8F, 0x82, 0x8E, 0x83, 0xE0, 0x54, 0x7F,
+/*0310*/0xF0, 0x12, 0x1E, 0x46, 0xE4, 0xF5, 0x0A, 0x20,
+ 0x03, 0x02, 0x80, 0x03, 0x30, 0x43, 0x03, 0x12,
+/*0320*/0x19, 0x95, 0x20, 0x02, 0x02, 0x80, 0x03, 0x30,
+ 0x42, 0x03, 0x12, 0x0C, 0x8F, 0x30, 0x30, 0x06,
+/*0330*/0x12, 0x19, 0x95, 0x12, 0x0C, 0x8F, 0x12, 0x0D,
+ 0x47, 0x12, 0x19, 0xF3, 0xE0, 0x54, 0xFB, 0xF0,
+/*0340*/0xE5, 0x0A, 0xC3, 0x94, 0x01, 0x40, 0x46, 0x43,
+ 0xE1, 0x08, 0x12, 0x19, 0xF3, 0xE0, 0x44, 0x04,
+/*0350*/0xF0, 0xE5, 0xE4, 0x20, 0xE7, 0x2A, 0x12, 0x1A,
+ 0x12, 0x75, 0x83, 0xD2, 0xE0, 0x54, 0x08, 0xD3,
+/*0360*/0x94, 0x00, 0x40, 0x04, 0x7F, 0x01, 0x80, 0x02,
+ 0x7F, 0x00, 0xE5, 0x0A, 0xC3, 0x94, 0x01, 0x40,
+/*0370*/0x04, 0x7E, 0x01, 0x80, 0x02, 0x7E, 0x00, 0xEF,
+ 0x5E, 0x60, 0x05, 0x12, 0x1D, 0xD7, 0x80, 0x17,
+/*0380*/0x12, 0x1A, 0x12, 0x75, 0x83, 0xD2, 0xE0, 0x44,
+ 0x08, 0xF0, 0x02, 0x03, 0xFB, 0x12, 0x1A, 0x12,
+/*0390*/0x75, 0x83, 0xD2, 0xE0, 0x54, 0xF7, 0xF0, 0x12,
+ 0x1E, 0x46, 0x7F, 0x08, 0x12, 0x17, 0x31, 0x74,
+/*03A0*/0x8E, 0xFE, 0x12, 0x1A, 0x12, 0x8E, 0x83, 0xE0,
+ 0xF5, 0x10, 0x54, 0xFE, 0xF0, 0xE5, 0x10, 0x44,
+/*03B0*/0x01, 0xFF, 0xE5, 0x08, 0xFD, 0xED, 0x44, 0x07,
+ 0xF5, 0x82, 0xEF, 0xF0, 0xE5, 0x10, 0x54, 0xFE,
+/*03C0*/0xFF, 0xED, 0x44, 0x07, 0xF5, 0x82, 0xEF, 0x12,
+ 0x1A, 0x11, 0x75, 0x83, 0x86, 0xE0, 0x44, 0x10,
+/*03D0*/0x12, 0x1A, 0x11, 0xE0, 0x44, 0x10, 0xF0, 0x12,
+ 0x19, 0xF3, 0xE0, 0x54, 0xFD, 0x44, 0x01, 0xFF,
+/*03E0*/0x12, 0x19, 0xF3, 0xEF, 0x12, 0x1A, 0x32, 0x30,
+ 0x32, 0x0C, 0xE5, 0x08, 0x44, 0x08, 0xF5, 0x82,
+/*03F0*/0x75, 0x83, 0x82, 0x74, 0x05, 0xF0, 0xAF, 0x0B,
+ 0x12, 0x18, 0xD7, 0x74, 0x10, 0x25, 0x08, 0xF5,
+/*0400*/0x08, 0x02, 0x00, 0x85, 0x05, 0x09, 0xE5, 0x09,
+ 0xD3, 0x94, 0x07, 0x50, 0x03, 0x02, 0x00, 0x82,
+/*0410*/0xE5, 0x7E, 0xD3, 0x94, 0x00, 0x40, 0x04, 0x7F,
+ 0x01, 0x80, 0x02, 0x7F, 0x00, 0xE5, 0x7E, 0xC3,
+/*0420*/0x94, 0xFA, 0x50, 0x04, 0x7E, 0x01, 0x80, 0x02,
+ 0x7E, 0x00, 0xEE, 0x5F, 0x60, 0x02, 0x05, 0x7E,
+/*0430*/0x30, 0x35, 0x0B, 0x43, 0xE1, 0x01, 0x7F, 0x09,
+ 0x12, 0x17, 0x31, 0x02, 0x00, 0x58, 0x53, 0xE1,
+/*0440*/0xFE, 0x02, 0x00, 0x58, 0x8E, 0x6A, 0x8F, 0x6B,
+ 0x8C, 0x6C, 0x8D, 0x6D, 0x75, 0x6E, 0x01, 0x75,
+/*0450*/0x6F, 0x01, 0x75, 0x70, 0x01, 0xE4, 0xF5, 0x73,
+ 0xF5, 0x74, 0xF5, 0x75, 0x90, 0x07, 0x2F, 0xF0,
+/*0460*/0xF5, 0x3C, 0xF5, 0x3E, 0xF5, 0x46, 0xF5, 0x47,
+ 0xF5, 0x3D, 0xF5, 0x3F, 0xF5, 0x6F, 0xE5, 0x6F,
+/*0470*/0x70, 0x0F, 0xE5, 0x6B, 0x45, 0x6A, 0x12, 0x07,
+ 0x2A, 0x75, 0x83, 0x80, 0x74, 0x3A, 0xF0, 0x80,
+/*0480*/0x09, 0x12, 0x07, 0x2A, 0x75, 0x83, 0x80, 0x74,
+ 0x1A, 0xF0, 0xE4, 0xF5, 0x6E, 0xC3, 0x74, 0x3F,
+/*0490*/0x95, 0x6E, 0xFF, 0x12, 0x08, 0x65, 0x75, 0x83,
+ 0x82, 0xEF, 0xF0, 0x12, 0x1A, 0x4D, 0x12, 0x08,
+/*04A0*/0xC6, 0xE5, 0x33, 0xF0, 0x12, 0x08, 0xFA, 0x12,
+ 0x08, 0xB1, 0x40, 0xE1, 0xE5, 0x6F, 0x70, 0x0B,
+/*04B0*/0x12, 0x07, 0x2A, 0x75, 0x83, 0x80, 0x74, 0x36,
+ 0xF0, 0x80, 0x09, 0x12, 0x07, 0x2A, 0x75, 0x83,
+/*04C0*/0x80, 0x74, 0x16, 0xF0, 0x75, 0x6E, 0x01, 0x12,
+ 0x07, 0x2A, 0x75, 0x83, 0xB4, 0xE5, 0x6E, 0xF0,
+/*04D0*/0x12, 0x1A, 0x4D, 0x74, 0x3F, 0x25, 0x6E, 0xF5,
+ 0x82, 0xE4, 0x34, 0x00, 0xF5, 0x83, 0xE5, 0x33,
+/*04E0*/0xF0, 0x74, 0xBF, 0x25, 0x6E, 0xF5, 0x82, 0xE4,
+ 0x34, 0x00, 0x12, 0x08, 0xB1, 0x40, 0xD8, 0xE4,
+/*04F0*/0xF5, 0x70, 0xF5, 0x46, 0xF5, 0x47, 0xF5, 0x6E,
+ 0x12, 0x08, 0xFA, 0xF5, 0x83, 0xE0, 0xFE, 0x12,
+/*0500*/0x08, 0xC6, 0xE0, 0x7C, 0x00, 0x24, 0x00, 0xFF,
+ 0xEC, 0x3E, 0xFE, 0xAD, 0x3B, 0xD3, 0xEF, 0x9D,
+/*0510*/0xEE, 0x9C, 0x50, 0x04, 0x7B, 0x01, 0x80, 0x02,
+ 0x7B, 0x00, 0xE5, 0x70, 0x70, 0x04, 0x7A, 0x01,
+/*0520*/0x80, 0x02, 0x7A, 0x00, 0xEB, 0x5A, 0x60, 0x06,
+ 0x85, 0x6E, 0x46, 0x75, 0x70, 0x01, 0xD3, 0xEF,
+/*0530*/0x9D, 0xEE, 0x9C, 0x50, 0x04, 0x7F, 0x01, 0x80,
+ 0x02, 0x7F, 0x00, 0xE5, 0x70, 0xB4, 0x01, 0x04,
+/*0540*/0x7E, 0x01, 0x80, 0x02, 0x7E, 0x00, 0xEF, 0x5E,
+ 0x60, 0x03, 0x85, 0x6E, 0x47, 0x05, 0x6E, 0xE5,
+/*0550*/0x6E, 0x64, 0x7F, 0x70, 0xA3, 0xE5, 0x46, 0x60,
+ 0x05, 0xE5, 0x47, 0xB4, 0x7E, 0x03, 0x85, 0x46,
+/*0560*/0x47, 0xE5, 0x6F, 0x70, 0x08, 0x85, 0x46, 0x76,
+ 0x85, 0x47, 0x77, 0x80, 0x0E, 0xC3, 0x74, 0x7F,
+/*0570*/0x95, 0x46, 0xF5, 0x78, 0xC3, 0x74, 0x7F, 0x95,
+ 0x47, 0xF5, 0x79, 0xE5, 0x6F, 0x70, 0x37, 0xE5,
+/*0580*/0x46, 0x65, 0x47, 0x70, 0x0C, 0x75, 0x73, 0x01,
+ 0x75, 0x74, 0x01, 0xF5, 0x3C, 0xF5, 0x3D, 0x80,
+/*0590*/0x35, 0xE4, 0xF5, 0x4E, 0xC3, 0xE5, 0x47, 0x95,
+ 0x46, 0xF5, 0x3C, 0xC3, 0x13, 0xF5, 0x71, 0x25,
+/*05A0*/0x46, 0xF5, 0x72, 0xC3, 0x94, 0x3F, 0x40, 0x05,
+ 0xE4, 0xF5, 0x3D, 0x80, 0x40, 0xC3, 0x74, 0x3F,
+/*05B0*/0x95, 0x72, 0xF5, 0x3D, 0x80, 0x37, 0xE5, 0x46,
+ 0x65, 0x47, 0x70, 0x0F, 0x75, 0x73, 0x01, 0x75,
+/*05C0*/0x75, 0x01, 0xF5, 0x3E, 0xF5, 0x3F, 0x75, 0x4E,
+ 0x01, 0x80, 0x22, 0xE4, 0xF5, 0x4E, 0xC3, 0xE5,
+/*05D0*/0x47, 0x95, 0x46, 0xF5, 0x3E, 0xC3, 0x13, 0xF5,
+ 0x71, 0x25, 0x46, 0xF5, 0x72, 0xD3, 0x94, 0x3F,
+/*05E0*/0x50, 0x05, 0xE4, 0xF5, 0x3F, 0x80, 0x06, 0xE5,
+ 0x72, 0x24, 0xC1, 0xF5, 0x3F, 0x05, 0x6F, 0xE5,
+/*05F0*/0x6F, 0xC3, 0x94, 0x02, 0x50, 0x03, 0x02, 0x04,
+ 0x6E, 0xE5, 0x6D, 0x45, 0x6C, 0x70, 0x02, 0x80,
+/*0600*/0x04, 0xE5, 0x74, 0x45, 0x75, 0x90, 0x07, 0x2F,
+ 0xF0, 0x7F, 0x01, 0xE5, 0x3E, 0x60, 0x04, 0xE5,
+/*0610*/0x3C, 0x70, 0x14, 0xE4, 0xF5, 0x3C, 0xF5, 0x3D,
+ 0xF5, 0x3E, 0xF5, 0x3F, 0x12, 0x08, 0xD2, 0x70,
+/*0620*/0x04, 0xF0, 0x02, 0x06, 0xA4, 0x80, 0x7A, 0xE5,
+ 0x3C, 0xC3, 0x95, 0x3E, 0x40, 0x07, 0xE5, 0x3C,
+/*0630*/0x95, 0x3E, 0xFF, 0x80, 0x06, 0xC3, 0xE5, 0x3E,
+ 0x95, 0x3C, 0xFF, 0xE5, 0x76, 0xD3, 0x95, 0x79,
+/*0640*/0x40, 0x05, 0x85, 0x76, 0x7A, 0x80, 0x03, 0x85,
+ 0x79, 0x7A, 0xE5, 0x77, 0xC3, 0x95, 0x78, 0x50,
+/*0650*/0x05, 0x85, 0x77, 0x7B, 0x80, 0x03, 0x85, 0x78,
+ 0x7B, 0xE5, 0x7B, 0xD3, 0x95, 0x7A, 0x40, 0x30,
+/*0660*/0xE5, 0x7B, 0x95, 0x7A, 0xF5, 0x3C, 0xF5, 0x3E,
+ 0xC3, 0xE5, 0x7B, 0x95, 0x7A, 0x90, 0x07, 0x19,
+/*0670*/0xF0, 0xE5, 0x3C, 0xC3, 0x13, 0xF5, 0x71, 0x25,
+ 0x7A, 0xF5, 0x72, 0xC3, 0x94, 0x3F, 0x40, 0x05,
+/*0680*/0xE4, 0xF5, 0x3D, 0x80, 0x1F, 0xC3, 0x74, 0x3F,
+ 0x95, 0x72, 0xF5, 0x3D, 0xF5, 0x3F, 0x80, 0x14,
+/*0690*/0xE4, 0xF5, 0x3C, 0xF5, 0x3E, 0x90, 0x07, 0x19,
+ 0xF0, 0x12, 0x08, 0xD2, 0x70, 0x03, 0xF0, 0x80,
+/*06A0*/0x03, 0x74, 0x01, 0xF0, 0x12, 0x08, 0x65, 0x75,
+ 0x83, 0xD0, 0xE0, 0x54, 0x0F, 0xFE, 0xAD, 0x3C,
+/*06B0*/0x70, 0x02, 0x7E, 0x07, 0xBE, 0x0F, 0x02, 0x7E,
+ 0x80, 0xEE, 0xFB, 0xEF, 0xD3, 0x9B, 0x74, 0x80,
+/*06C0*/0xF8, 0x98, 0x40, 0x1F, 0xE4, 0xF5, 0x3C, 0xF5,
+ 0x3E, 0x12, 0x08, 0xD2, 0x70, 0x03, 0xF0, 0x80,
+/*06D0*/0x12, 0x74, 0x01, 0xF0, 0xE5, 0x08, 0xFB, 0xEB,
+ 0x44, 0x07, 0xF5, 0x82, 0x75, 0x83, 0xD2, 0xE0,
+/*06E0*/0x44, 0x10, 0xF0, 0xE5, 0x08, 0xFB, 0xEB, 0x44,
+ 0x09, 0xF5, 0x82, 0x75, 0x83, 0x9E, 0xED, 0xF0,
+/*06F0*/0xEB, 0x44, 0x07, 0xF5, 0x82, 0x75, 0x83, 0xCA,
+ 0xED, 0xF0, 0x12, 0x08, 0x65, 0x75, 0x83, 0xCC,
+/*0700*/0xEF, 0xF0, 0x22, 0xE5, 0x08, 0x44, 0x07, 0xF5,
+ 0x82, 0x75, 0x83, 0xBC, 0xE0, 0x54, 0xF0, 0xF0,
+/*0710*/0xE5, 0x08, 0x44, 0x07, 0xF5, 0x82, 0x75, 0x83,
+ 0xBE, 0xE0, 0x54, 0xF0, 0xF0, 0xE5, 0x08, 0x44,
+/*0720*/0x07, 0xF5, 0x82, 0x75, 0x83, 0xC0, 0xE0, 0x54,
+ 0xF0, 0xF0, 0xE5, 0x08, 0x44, 0x07, 0xF5, 0x82,
+/*0730*/0x22, 0xF0, 0x90, 0x07, 0x28, 0xE0, 0xFE, 0xA3,
+ 0xE0, 0xF5, 0x82, 0x8E, 0x83, 0x22, 0x85, 0x42,
+/*0740*/0x42, 0x85, 0x41, 0x41, 0x85, 0x40, 0x40, 0x74,
+ 0xC0, 0x2F, 0xF5, 0x82, 0x74, 0x02, 0x3E, 0xF5,
+/*0750*/0x83, 0xE5, 0x42, 0xF0, 0x74, 0xE0, 0x2F, 0xF5,
+ 0x82, 0x74, 0x02, 0x3E, 0xF5, 0x83, 0x22, 0xE5,
+/*0760*/0x42, 0x29, 0xFD, 0xE4, 0x33, 0xFC, 0xE5, 0x3C,
+ 0xC3, 0x9D, 0xEC, 0x64, 0x80, 0xF8, 0x74, 0x80,
+/*0770*/0x98, 0x22, 0xF5, 0x83, 0xE0, 0x90, 0x07, 0x22,
+ 0x54, 0x1F, 0xFD, 0xE0, 0xFA, 0xA3, 0xE0, 0xF5,
+/*0780*/0x82, 0x8A, 0x83, 0xED, 0xF0, 0x22, 0x90, 0x07,
+ 0x22, 0xE0, 0xFC, 0xA3, 0xE0, 0xF5, 0x82, 0x8C,
+/*0790*/0x83, 0x22, 0x90, 0x07, 0x24, 0xFF, 0xED, 0x44,
+ 0x07, 0xCF, 0xF0, 0xA3, 0xEF, 0xF0, 0x22, 0x85,
+/*07A0*/0x38, 0x38, 0x85, 0x39, 0x39, 0x85, 0x3A, 0x3A,
+ 0x74, 0xC0, 0x2F, 0xF5, 0x82, 0x74, 0x02, 0x3E,
+/*07B0*/0xF5, 0x83, 0x22, 0x90, 0x07, 0x26, 0xFF, 0xED,
+ 0x44, 0x07, 0xCF, 0xF0, 0xA3, 0xEF, 0xF0, 0x22,
+/*07C0*/0xF0, 0x74, 0xA0, 0x2F, 0xF5, 0x82, 0x74, 0x02,
+ 0x3E, 0xF5, 0x83, 0x22, 0x74, 0xC0, 0x25, 0x11,
+/*07D0*/0xF5, 0x82, 0xE4, 0x34, 0x01, 0xF5, 0x83, 0x22,
+ 0x74, 0x00, 0x25, 0x11, 0xF5, 0x82, 0xE4, 0x34,
+/*07E0*/0x02, 0xF5, 0x83, 0x22, 0x74, 0x60, 0x25, 0x11,
+ 0xF5, 0x82, 0xE4, 0x34, 0x03, 0xF5, 0x83, 0x22,
+/*07F0*/0x74, 0x80, 0x25, 0x11, 0xF5, 0x82, 0xE4, 0x34,
+ 0x03, 0xF5, 0x83, 0x22, 0x74, 0xE0, 0x25, 0x11,
+/*0800*/0xF5, 0x82, 0xE4, 0x34, 0x03, 0xF5, 0x83, 0x22,
+ 0x74, 0x40, 0x25, 0x11, 0xF5, 0x82, 0xE4, 0x34,
+/*0810*/0x06, 0xF5, 0x83, 0x22, 0x74, 0x80, 0x2F, 0xF5,
+ 0x82, 0x74, 0x02, 0x3E, 0xF5, 0x83, 0x22, 0xAF,
+/*0820*/0x08, 0x7E, 0x00, 0xEF, 0x44, 0x07, 0xF5, 0x82,
+ 0x22, 0xF5, 0x83, 0xE5, 0x82, 0x44, 0x07, 0xF5,
+/*0830*/0x82, 0xE5, 0x40, 0xF0, 0x22, 0x74, 0x40, 0x25,
+ 0x11, 0xF5, 0x82, 0xE4, 0x34, 0x02, 0xF5, 0x83,
+/*0840*/0x22, 0x74, 0xC0, 0x25, 0x11, 0xF5, 0x82, 0xE4,
+ 0x34, 0x03, 0xF5, 0x83, 0x22, 0x74, 0x00, 0x25,
+/*0850*/0x11, 0xF5, 0x82, 0xE4, 0x34, 0x06, 0xF5, 0x83,
+ 0x22, 0x74, 0x20, 0x25, 0x11, 0xF5, 0x82, 0xE4,
+/*0860*/0x34, 0x06, 0xF5, 0x83, 0x22, 0xE5, 0x08, 0xFD,
+ 0xED, 0x44, 0x07, 0xF5, 0x82, 0x22, 0xE5, 0x41,
+/*0870*/0xF0, 0xE5, 0x65, 0x64, 0x01, 0x45, 0x64, 0x22,
+ 0x7E, 0x00, 0xFB, 0x7A, 0x00, 0xFD, 0x7C, 0x00,
+/*0880*/0x22, 0x74, 0x20, 0x25, 0x11, 0xF5, 0x82, 0xE4,
+ 0x34, 0x02, 0x22, 0x74, 0xA0, 0x25, 0x11, 0xF5,
+/*0890*/0x82, 0xE4, 0x34, 0x03, 0x22, 0x85, 0x3E, 0x42,
+ 0x85, 0x3F, 0x41, 0x8F, 0x40, 0x22, 0x85, 0x3C,
+/*08A0*/0x42, 0x85, 0x3D, 0x41, 0x8F, 0x40, 0x22, 0x75,
+ 0x45, 0x3F, 0x90, 0x07, 0x20, 0xE4, 0xF0, 0xA3,
+/*08B0*/0x22, 0xF5, 0x83, 0xE5, 0x32, 0xF0, 0x05, 0x6E,
+ 0xE5, 0x6E, 0xC3, 0x94, 0x40, 0x22, 0xF0, 0xE5,
+/*08C0*/0x08, 0x44, 0x06, 0xF5, 0x82, 0x22, 0x74, 0x00,
+ 0x25, 0x6E, 0xF5, 0x82, 0xE4, 0x34, 0x00, 0xF5,
+/*08D0*/0x83, 0x22, 0xE5, 0x6D, 0x45, 0x6C, 0x90, 0x07,
+ 0x2F, 0x22, 0xE4, 0xF9, 0xE5, 0x3C, 0xD3, 0x95,
+/*08E0*/0x3E, 0x22, 0x74, 0x80, 0x2E, 0xF5, 0x82, 0xE4,
+ 0x34, 0x02, 0xF5, 0x83, 0xE0, 0x22, 0x74, 0xA0,
+/*08F0*/0x2E, 0xF5, 0x82, 0xE4, 0x34, 0x02, 0xF5, 0x83,
+ 0xE0, 0x22, 0x74, 0x80, 0x25, 0x6E, 0xF5, 0x82,
+/*0900*/0xE4, 0x34, 0x00, 0x22, 0x25, 0x42, 0xFD, 0xE4,
+ 0x33, 0xFC, 0x22, 0x85, 0x42, 0x42, 0x85, 0x41,
+/*0910*/0x41, 0x85, 0x40, 0x40, 0x22, 0xED, 0x4C, 0x60,
+ 0x03, 0x02, 0x09, 0xE5, 0xEF, 0x4E, 0x70, 0x37,
+/*0920*/0x90, 0x07, 0x26, 0x12, 0x07, 0x89, 0xE0, 0xFD,
+ 0x12, 0x07, 0xCC, 0xED, 0xF0, 0x90, 0x07, 0x28,
+/*0930*/0x12, 0x07, 0x89, 0xE0, 0xFD, 0x12, 0x07, 0xD8,
+ 0xED, 0xF0, 0x12, 0x07, 0x86, 0xE0, 0x54, 0x1F,
+/*0940*/0xFD, 0x12, 0x08, 0x81, 0xF5, 0x83, 0xED, 0xF0,
+ 0x90, 0x07, 0x24, 0x12, 0x07, 0x89, 0xE0, 0x54,
+/*0950*/0x1F, 0xFD, 0x12, 0x08, 0x35, 0xED, 0xF0, 0xEF,
+ 0x64, 0x04, 0x4E, 0x70, 0x37, 0x90, 0x07, 0x26,
+/*0960*/0x12, 0x07, 0x89, 0xE0, 0xFD, 0x12, 0x07, 0xE4,
+ 0xED, 0xF0, 0x90, 0x07, 0x28, 0x12, 0x07, 0x89,
+/*0970*/0xE0, 0xFD, 0x12, 0x07, 0xF0, 0xED, 0xF0, 0x12,
+ 0x07, 0x86, 0xE0, 0x54, 0x1F, 0xFD, 0x12, 0x08,
+/*0980*/0x8B, 0xF5, 0x83, 0xED, 0xF0, 0x90, 0x07, 0x24,
+ 0x12, 0x07, 0x89, 0xE0, 0x54, 0x1F, 0xFD, 0x12,
+/*0990*/0x08, 0x41, 0xED, 0xF0, 0xEF, 0x64, 0x01, 0x4E,
+ 0x70, 0x04, 0x7D, 0x01, 0x80, 0x02, 0x7D, 0x00,
+/*09A0*/0xEF, 0x64, 0x02, 0x4E, 0x70, 0x04, 0x7F, 0x01,
+ 0x80, 0x02, 0x7F, 0x00, 0xEF, 0x4D, 0x60, 0x78,
+/*09B0*/0x90, 0x07, 0x26, 0x12, 0x07, 0x35, 0xE0, 0xFF,
+ 0x12, 0x07, 0xFC, 0xEF, 0x12, 0x07, 0x31, 0xE0,
+/*09C0*/0xFF, 0x12, 0x08, 0x08, 0xEF, 0xF0, 0x90, 0x07,
+ 0x22, 0x12, 0x07, 0x35, 0xE0, 0x54, 0x1F, 0xFF,
+/*09D0*/0x12, 0x08, 0x4D, 0xEF, 0xF0, 0x90, 0x07, 0x24,
+ 0x12, 0x07, 0x35, 0xE0, 0x54, 0x1F, 0xFF, 0x12,
+/*09E0*/0x08, 0x59, 0xEF, 0xF0, 0x22, 0x12, 0x07, 0xCC,
+ 0xE4, 0xF0, 0x12, 0x07, 0xD8, 0xE4, 0xF0, 0x12,
+/*09F0*/0x08, 0x81, 0xF5, 0x83, 0xE4, 0xF0, 0x12, 0x08,
+ 0x35, 0x74, 0x14, 0xF0, 0x12, 0x07, 0xE4, 0xE4,
+/*0A00*/0xF0, 0x12, 0x07, 0xF0, 0xE4, 0xF0, 0x12, 0x08,
+ 0x8B, 0xF5, 0x83, 0xE4, 0xF0, 0x12, 0x08, 0x41,
+/*0A10*/0x74, 0x14, 0xF0, 0x12, 0x07, 0xFC, 0xE4, 0xF0,
+ 0x12, 0x08, 0x08, 0xE4, 0xF0, 0x12, 0x08, 0x4D,
+/*0A20*/0xE4, 0xF0, 0x12, 0x08, 0x59, 0x74, 0x14, 0xF0,
+ 0x22, 0x53, 0xF9, 0xF7, 0x75, 0xFC, 0x10, 0xE4,
+/*0A30*/0xF5, 0xFD, 0x75, 0xFE, 0x30, 0xF5, 0xFF, 0xE5,
+ 0xE7, 0x20, 0xE7, 0x03, 0x43, 0xF9, 0x08, 0xE5,
+/*0A40*/0xE6, 0x20, 0xE7, 0x0B, 0x78, 0xFF, 0xE4, 0xF6,
+ 0xD8, 0xFD, 0x53, 0xE6, 0xFE, 0x80, 0x09, 0x78,
+/*0A50*/0x08, 0xE4, 0xF6, 0xD8, 0xFD, 0x53, 0xE6, 0xFE,
+ 0x75, 0x81, 0x80, 0xE4, 0xF5, 0xA8, 0xD2, 0xA8,
+/*0A60*/0xC2, 0xA9, 0xD2, 0xAF, 0xE5, 0xE2, 0x20, 0xE5,
+ 0x05, 0x20, 0xE6, 0x02, 0x80, 0x03, 0x43, 0xE1,
+/*0A70*/0x02, 0xE5, 0xE2, 0x20, 0xE0, 0x0E, 0x90, 0x00,
+ 0x00, 0x7F, 0x00, 0x7E, 0x08, 0xE4, 0xF0, 0xA3,
+/*0A80*/0xDF, 0xFC, 0xDE, 0xFA, 0x02, 0x0A, 0xDB, 0x43,
+ 0xFA, 0x01, 0xC0, 0xE0, 0xC0, 0xF0, 0xC0, 0x83,
+/*0A90*/0xC0, 0x82, 0xC0, 0xD0, 0x12, 0x1C, 0xE7, 0xD0,
+ 0xD0, 0xD0, 0x82, 0xD0, 0x83, 0xD0, 0xF0, 0xD0,
+/*0AA0*/0xE0, 0x53, 0xFA, 0xFE, 0x32, 0x02, 0x1B, 0x55,
+ 0xE4, 0x93, 0xA3, 0xF8, 0xE4, 0x93, 0xA3, 0xF6,
+/*0AB0*/0x08, 0xDF, 0xF9, 0x80, 0x29, 0xE4, 0x93, 0xA3,
+ 0xF8, 0x54, 0x07, 0x24, 0x0C, 0xC8, 0xC3, 0x33,
+/*0AC0*/0xC4, 0x54, 0x0F, 0x44, 0x20, 0xC8, 0x83, 0x40,
+ 0x04, 0xF4, 0x56, 0x80, 0x01, 0x46, 0xF6, 0xDF,
+/*0AD0*/0xE4, 0x80, 0x0B, 0x01, 0x02, 0x04, 0x08, 0x10,
+ 0x20, 0x40, 0x80, 0x90, 0x00, 0x3F, 0xE4, 0x7E,
+/*0AE0*/0x01, 0x93, 0x60, 0xC1, 0xA3, 0xFF, 0x54, 0x3F,
+ 0x30, 0xE5, 0x09, 0x54, 0x1F, 0xFE, 0xE4, 0x93,
+/*0AF0*/0xA3, 0x60, 0x01, 0x0E, 0xCF, 0x54, 0xC0, 0x25,
+ 0xE0, 0x60, 0xAD, 0x40, 0xB8, 0x80, 0xFE, 0x8C,
+/*0B00*/0x64, 0x8D, 0x65, 0x8A, 0x66, 0x8B, 0x67, 0xE4,
+ 0xF5, 0x69, 0xEF, 0x4E, 0x70, 0x03, 0x02, 0x1D,
+/*0B10*/0x55, 0xE4, 0xF5, 0x68, 0xE5, 0x67, 0x45, 0x66,
+ 0x70, 0x32, 0x12, 0x07, 0x2A, 0x75, 0x83, 0x90,
+/*0B20*/0xE4, 0x12, 0x07, 0x29, 0x75, 0x83, 0xC2, 0xE4,
+ 0x12, 0x07, 0x29, 0x75, 0x83, 0xC4, 0xE4, 0x12,
+/*0B30*/0x08, 0x70, 0x70, 0x29, 0x12, 0x07, 0x2A, 0x75,
+ 0x83, 0x92, 0xE4, 0x12, 0x07, 0x29, 0x75, 0x83,
+/*0B40*/0xC6, 0xE4, 0x12, 0x07, 0x29, 0x75, 0x83, 0xC8,
+ 0xE4, 0xF0, 0x80, 0x11, 0x90, 0x07, 0x26, 0x12,
+/*0B50*/0x07, 0x35, 0xE4, 0x12, 0x08, 0x70, 0x70, 0x05,
+ 0x12, 0x07, 0x32, 0xE4, 0xF0, 0x12, 0x1D, 0x55,
+/*0B60*/0x12, 0x1E, 0xBF, 0xE5, 0x67, 0x45, 0x66, 0x70,
+ 0x33, 0x12, 0x07, 0x2A, 0x75, 0x83, 0x90, 0xE5,
+/*0B70*/0x41, 0x12, 0x07, 0x29, 0x75, 0x83, 0xC2, 0xE5,
+ 0x41, 0x12, 0x07, 0x29, 0x75, 0x83, 0xC4, 0x12,
+/*0B80*/0x08, 0x6E, 0x70, 0x29, 0x12, 0x07, 0x2A, 0x75,
+ 0x83, 0x92, 0xE5, 0x40, 0x12, 0x07, 0x29, 0x75,
+/*0B90*/0x83, 0xC6, 0xE5, 0x40, 0x12, 0x07, 0x29, 0x75,
+ 0x83, 0xC8, 0x80, 0x0E, 0x90, 0x07, 0x26, 0x12,
+/*0BA0*/0x07, 0x35, 0x12, 0x08, 0x6E, 0x70, 0x06, 0x12,
+ 0x07, 0x32, 0xE5, 0x40, 0xF0, 0xAF, 0x69, 0x7E,
+/*0BB0*/0x00, 0xAD, 0x67, 0xAC, 0x66, 0x12, 0x04, 0x44,
+ 0x12, 0x07, 0x2A, 0x75, 0x83, 0xCA, 0xE0, 0xD3,
+/*0BC0*/0x94, 0x00, 0x50, 0x0C, 0x05, 0x68, 0xE5, 0x68,
+ 0xC3, 0x94, 0x05, 0x50, 0x03, 0x02, 0x0B, 0x14,
+/*0BD0*/0x22, 0x8C, 0x60, 0x8D, 0x61, 0x12, 0x08, 0xDA,
+ 0x74, 0x20, 0x40, 0x0D, 0x2F, 0xF5, 0x82, 0x74,
+/*0BE0*/0x03, 0x3E, 0xF5, 0x83, 0xE5, 0x3E, 0xF0, 0x80,
+ 0x0B, 0x2F, 0xF5, 0x82, 0x74, 0x03, 0x3E, 0xF5,
+/*0BF0*/0x83, 0xE5, 0x3C, 0xF0, 0xE5, 0x3C, 0xD3, 0x95,
+ 0x3E, 0x40, 0x3C, 0xE5, 0x61, 0x45, 0x60, 0x70,
+/*0C00*/0x10, 0xE9, 0x12, 0x09, 0x04, 0xE5, 0x3E, 0x12,
+ 0x07, 0x68, 0x40, 0x3B, 0x12, 0x08, 0x95, 0x80,
+/*0C10*/0x18, 0xE5, 0x3E, 0xC3, 0x95, 0x38, 0x40, 0x1D,
+ 0x85, 0x3E, 0x38, 0xE5, 0x3E, 0x60, 0x05, 0x85,
+/*0C20*/0x3F, 0x39, 0x80, 0x03, 0x85, 0x39, 0x39, 0x8F,
+ 0x3A, 0x12, 0x08, 0x14, 0xE5, 0x3E, 0x12, 0x07,
+/*0C30*/0xC0, 0xE5, 0x3F, 0xF0, 0x22, 0x80, 0x43, 0xE5,
+ 0x61, 0x45, 0x60, 0x70, 0x19, 0x12, 0x07, 0x5F,
+/*0C40*/0x40, 0x05, 0x12, 0x08, 0x9E, 0x80, 0x27, 0x12,
+ 0x09, 0x0B, 0x12, 0x08, 0x14, 0xE5, 0x42, 0x12,
+/*0C50*/0x07, 0xC0, 0xE5, 0x41, 0xF0, 0x22, 0xE5, 0x3C,
+ 0xC3, 0x95, 0x38, 0x40, 0x1D, 0x85, 0x3C, 0x38,
+/*0C60*/0xE5, 0x3C, 0x60, 0x05, 0x85, 0x3D, 0x39, 0x80,
+ 0x03, 0x85, 0x39, 0x39, 0x8F, 0x3A, 0x12, 0x08,
+/*0C70*/0x14, 0xE5, 0x3C, 0x12, 0x07, 0xC0, 0xE5, 0x3D,
+ 0xF0, 0x22, 0x85, 0x38, 0x38, 0x85, 0x39, 0x39,
+/*0C80*/0x85, 0x3A, 0x3A, 0x12, 0x08, 0x14, 0xE5, 0x38,
+ 0x12, 0x07, 0xC0, 0xE5, 0x39, 0xF0, 0x22, 0x7F,
+/*0C90*/0x06, 0x12, 0x17, 0x31, 0x12, 0x1D, 0x23, 0x12,
+ 0x0E, 0x04, 0x12, 0x0E, 0x33, 0xE0, 0x44, 0x0A,
+/*0CA0*/0xF0, 0x74, 0x8E, 0xFE, 0x12, 0x0E, 0x04, 0x12,
+ 0x0E, 0x0B, 0xEF, 0xF0, 0xE5, 0x28, 0x30, 0xE5,
+/*0CB0*/0x03, 0xD3, 0x80, 0x01, 0xC3, 0x40, 0x05, 0x75,
+ 0x14, 0x20, 0x80, 0x03, 0x75, 0x14, 0x08, 0x12,
+/*0CC0*/0x0E, 0x04, 0x75, 0x83, 0x8A, 0xE5, 0x14, 0xF0,
+ 0xB4, 0xFF, 0x05, 0x75, 0x12, 0x80, 0x80, 0x06,
+/*0CD0*/0xE5, 0x14, 0xC3, 0x13, 0xF5, 0x12, 0xE4, 0xF5,
+ 0x16, 0xF5, 0x7F, 0x12, 0x19, 0x36, 0x12, 0x13,
+/*0CE0*/0xA3, 0xE5, 0x0A, 0xC3, 0x94, 0x01, 0x50, 0x09,
+ 0x05, 0x16, 0xE5, 0x16, 0xC3, 0x94, 0x14, 0x40,
+/*0CF0*/0xEA, 0xE5, 0xE4, 0x20, 0xE7, 0x28, 0x12, 0x0E,
+ 0x04, 0x75, 0x83, 0xD2, 0xE0, 0x54, 0x08, 0xD3,
+/*0D00*/0x94, 0x00, 0x40, 0x04, 0x7F, 0x01, 0x80, 0x02,
+ 0x7F, 0x00, 0xE5, 0x0A, 0xC3, 0x94, 0x01, 0x40,
+/*0D10*/0x04, 0x7E, 0x01, 0x80, 0x02, 0x7E, 0x00, 0xEF,
+ 0x5E, 0x60, 0x03, 0x12, 0x1D, 0xD7, 0xE5, 0x7F,
+/*0D20*/0xC3, 0x94, 0x11, 0x40, 0x14, 0x12, 0x0E, 0x04,
+ 0x75, 0x83, 0xD2, 0xE0, 0x44, 0x80, 0xF0, 0xE5,
+/*0D30*/0xE4, 0x20, 0xE7, 0x0F, 0x12, 0x1D, 0xD7, 0x80,
+ 0x0A, 0x12, 0x0E, 0x04, 0x75, 0x83, 0xD2, 0xE0,
+/*0D40*/0x54, 0x7F, 0xF0, 0x12, 0x1D, 0x23, 0x22, 0x74,
+ 0x8A, 0x85, 0x08, 0x82, 0xF5, 0x83, 0xE5, 0x17,
+/*0D50*/0xF0, 0x12, 0x0E, 0x3A, 0xE4, 0xF0, 0x90, 0x07,
+ 0x02, 0xE0, 0x12, 0x0E, 0x17, 0x75, 0x83, 0x90,
+/*0D60*/0xEF, 0xF0, 0x74, 0x92, 0xFE, 0xE5, 0x08, 0x44,
+ 0x07, 0xFF, 0xF5, 0x82, 0x8E, 0x83, 0xE0, 0x54,
+/*0D70*/0xC0, 0xFD, 0x90, 0x07, 0x03, 0xE0, 0x54, 0x3F,
+ 0x4D, 0x8F, 0x82, 0x8E, 0x83, 0xF0, 0x90, 0x07,
+/*0D80*/0x04, 0xE0, 0x12, 0x0E, 0x17, 0x75, 0x83, 0x82,
+ 0xEF, 0xF0, 0x90, 0x07, 0x05, 0xE0, 0xFF, 0xED,
+/*0D90*/0x44, 0x07, 0xF5, 0x82, 0x75, 0x83, 0xB4, 0xEF,
+ 0x12, 0x0E, 0x03, 0x75, 0x83, 0x80, 0xE0, 0x54,
+/*0DA0*/0xBF, 0xF0, 0x30, 0x37, 0x0A, 0x12, 0x0E, 0x91,
+ 0x75, 0x83, 0x94, 0xE0, 0x44, 0x80, 0xF0, 0x30,
+/*0DB0*/0x38, 0x0A, 0x12, 0x0E, 0x91, 0x75, 0x83, 0x92,
+ 0xE0, 0x44, 0x80, 0xF0, 0xE5, 0x28, 0x30, 0xE4,
+/*0DC0*/0x1A, 0x20, 0x39, 0x0A, 0x12, 0x0E, 0x04, 0x75,
+ 0x83, 0x88, 0xE0, 0x54, 0x7F, 0xF0, 0x20, 0x3A,
+/*0DD0*/0x0A, 0x12, 0x0E, 0x04, 0x75, 0x83, 0x88, 0xE0,
+ 0x54, 0xBF, 0xF0, 0x74, 0x8C, 0xFE, 0x12, 0x0E,
+/*0DE0*/0x04, 0x8E, 0x83, 0xE0, 0x54, 0x0F, 0x12, 0x0E,
+ 0x03, 0x75, 0x83, 0x86, 0xE0, 0x54, 0xBF, 0xF0,
+/*0DF0*/0xE5, 0x08, 0x44, 0x06, 0x12, 0x0D, 0xFD, 0x75,
+ 0x83, 0x8A, 0xE4, 0xF0, 0x22, 0xF5, 0x82, 0x75,
+/*0E00*/0x83, 0x82, 0xE4, 0xF0, 0xE5, 0x08, 0x44, 0x07,
+ 0xF5, 0x82, 0x22, 0x8E, 0x83, 0xE0, 0xF5, 0x10,
+/*0E10*/0x54, 0xFE, 0xF0, 0xE5, 0x10, 0x44, 0x01, 0xFF,
+ 0xE5, 0x08, 0xFD, 0xED, 0x44, 0x07, 0xF5, 0x82,
+/*0E20*/0x22, 0xE5, 0x15, 0xC4, 0x54, 0x07, 0xFF, 0xE5,
+ 0x08, 0xFD, 0xED, 0x44, 0x08, 0xF5, 0x82, 0x75,
+/*0E30*/0x83, 0x82, 0x22, 0x75, 0x83, 0x80, 0xE0, 0x44,
+ 0x40, 0xF0, 0xE5, 0x08, 0x44, 0x08, 0xF5, 0x82,
+/*0E40*/0x75, 0x83, 0x8A, 0x22, 0xE5, 0x16, 0x25, 0xE0,
+ 0x25, 0xE0, 0x24, 0xAF, 0xF5, 0x82, 0xE4, 0x34,
+/*0E50*/0x1A, 0xF5, 0x83, 0xE4, 0x93, 0xF5, 0x0D, 0x22,
+ 0x43, 0xE1, 0x10, 0x43, 0xE1, 0x80, 0x53, 0xE1,
+/*0E60*/0xFD, 0x85, 0xE1, 0x10, 0x22, 0xE5, 0x16, 0x25,
+ 0xE0, 0x25, 0xE0, 0x24, 0xB2, 0xF5, 0x82, 0xE4,
+/*0E70*/0x34, 0x1A, 0xF5, 0x83, 0xE4, 0x93, 0x22, 0x85,
+ 0x55, 0x82, 0x85, 0x54, 0x83, 0xE5, 0x15, 0xF0,
+/*0E80*/0x22, 0xE5, 0xE2, 0x54, 0x20, 0xD3, 0x94, 0x00,
+ 0x22, 0xE5, 0xE2, 0x54, 0x40, 0xD3, 0x94, 0x00,
+/*0E90*/0x22, 0xE5, 0x08, 0x44, 0x06, 0xF5, 0x82, 0x22,
+ 0xFD, 0xE5, 0x08, 0xFB, 0xEB, 0x44, 0x07, 0xF5,
+/*0EA0*/0x82, 0x22, 0x53, 0xF9, 0xF7, 0x75, 0xFE, 0x30,
+ 0x22, 0xEF, 0x4E, 0x70, 0x26, 0x12, 0x07, 0xCC,
+/*0EB0*/0xE0, 0xFD, 0x90, 0x07, 0x26, 0x12, 0x07, 0x7B,
+ 0x12, 0x07, 0xD8, 0xE0, 0xFD, 0x90, 0x07, 0x28,
+/*0EC0*/0x12, 0x07, 0x7B, 0x12, 0x08, 0x81, 0x12, 0x07,
+ 0x72, 0x12, 0x08, 0x35, 0xE0, 0x90, 0x07, 0x24,
+/*0ED0*/0x12, 0x07, 0x78, 0xEF, 0x64, 0x04, 0x4E, 0x70,
+ 0x29, 0x12, 0x07, 0xE4, 0xE0, 0xFD, 0x90, 0x07,
+/*0EE0*/0x26, 0x12, 0x07, 0x7B, 0x12, 0x07, 0xF0, 0xE0,
+ 0xFD, 0x90, 0x07, 0x28, 0x12, 0x07, 0x7B, 0x12,
+/*0EF0*/0x08, 0x8B, 0x12, 0x07, 0x72, 0x12, 0x08, 0x41,
+ 0xE0, 0x54, 0x1F, 0xFD, 0x90, 0x07, 0x24, 0x12,
+/*0F00*/0x07, 0x7B, 0xEF, 0x64, 0x01, 0x4E, 0x70, 0x04,
+ 0x7D, 0x01, 0x80, 0x02, 0x7D, 0x00, 0xEF, 0x64,
+/*0F10*/0x02, 0x4E, 0x70, 0x04, 0x7F, 0x01, 0x80, 0x02,
+ 0x7F, 0x00, 0xEF, 0x4D, 0x60, 0x35, 0x12, 0x07,
+/*0F20*/0xFC, 0xE0, 0xFF, 0x90, 0x07, 0x26, 0x12, 0x07,
+ 0x89, 0xEF, 0xF0, 0x12, 0x08, 0x08, 0xE0, 0xFF,
+/*0F30*/0x90, 0x07, 0x28, 0x12, 0x07, 0x89, 0xEF, 0xF0,
+ 0x12, 0x08, 0x4D, 0xE0, 0x54, 0x1F, 0xFF, 0x12,
+/*0F40*/0x07, 0x86, 0xEF, 0xF0, 0x12, 0x08, 0x59, 0xE0,
+ 0x54, 0x1F, 0xFF, 0x90, 0x07, 0x24, 0x12, 0x07,
+/*0F50*/0x89, 0xEF, 0xF0, 0x22, 0xE4, 0xF5, 0x53, 0x12,
+ 0x0E, 0x81, 0x40, 0x04, 0x7F, 0x01, 0x80, 0x02,
+/*0F60*/0x7F, 0x00, 0x12, 0x0E, 0x89, 0x40, 0x04, 0x7E,
+ 0x01, 0x80, 0x02, 0x7E, 0x00, 0xEE, 0x4F, 0x70,
+/*0F70*/0x03, 0x02, 0x0F, 0xF6, 0x85, 0xE1, 0x10, 0x43,
+ 0xE1, 0x02, 0x53, 0xE1, 0x0F, 0x85, 0xE1, 0x10,
+/*0F80*/0xE4, 0xF5, 0x51, 0xE5, 0xE3, 0x54, 0x3F, 0xF5,
+ 0x52, 0x12, 0x0E, 0x89, 0x40, 0x1D, 0xAD, 0x52,
+/*0F90*/0xAF, 0x51, 0x12, 0x11, 0x18, 0xEF, 0x60, 0x08,
+ 0x85, 0xE1, 0x10, 0x43, 0xE1, 0x40, 0x80, 0x0B,
+/*0FA0*/0x53, 0xE1, 0xBF, 0x12, 0x0E, 0x58, 0x12, 0x00,
+ 0x06, 0x80, 0xFB, 0xE5, 0xE3, 0x54, 0x3F, 0xF5,
+/*0FB0*/0x51, 0xE5, 0xE4, 0x54, 0x3F, 0xF5, 0x52, 0x12,
+ 0x0E, 0x81, 0x40, 0x1D, 0xAD, 0x52, 0xAF, 0x51,
+/*0FC0*/0x12, 0x11, 0x18, 0xEF, 0x60, 0x08, 0x85, 0xE1,
+ 0x10, 0x43, 0xE1, 0x20, 0x80, 0x0B, 0x53, 0xE1,
+/*0FD0*/0xDF, 0x12, 0x0E, 0x58, 0x12, 0x00, 0x06, 0x80,
+ 0xFB, 0x12, 0x0E, 0x81, 0x40, 0x04, 0x7F, 0x01,
+/*0FE0*/0x80, 0x02, 0x7F, 0x00, 0x12, 0x0E, 0x89, 0x40,
+ 0x04, 0x7E, 0x01, 0x80, 0x02, 0x7E, 0x00, 0xEE,
+/*0FF0*/0x4F, 0x60, 0x03, 0x12, 0x0E, 0x5B, 0x22, 0x12,
+ 0x0E, 0x21, 0xEF, 0xF0, 0x12, 0x10, 0x91, 0x22,
+/*1000*/0x02, 0x11, 0x00, 0x02, 0x10, 0x40, 0x02, 0x10,
+ 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/*1010*/0x01, 0x20, 0x01, 0x20, 0xE4, 0xF5, 0x57, 0x12,
+ 0x16, 0xBD, 0x12, 0x16, 0x44, 0xE4, 0x12, 0x10,
+/*1020*/0x56, 0x12, 0x14, 0xB7, 0x90, 0x07, 0x26, 0x12,
+ 0x07, 0x35, 0xE4, 0x12, 0x07, 0x31, 0xE4, 0xF0,
+/*1030*/0x12, 0x10, 0x56, 0x12, 0x14, 0xB7, 0x90, 0x07,
+ 0x26, 0x12, 0x07, 0x35, 0xE5, 0x41, 0x12, 0x07,
+/*1040*/0x31, 0xE5, 0x40, 0xF0, 0xAF, 0x57, 0x7E, 0x00,
+ 0xAD, 0x56, 0x7C, 0x00, 0x12, 0x04, 0x44, 0xAF,
+/*1050*/0x56, 0x7E, 0x00, 0x02, 0x11, 0xEE, 0xFF, 0x90,
+ 0x07, 0x20, 0xA3, 0xE0, 0xFD, 0xE4, 0xF5, 0x56,
+/*1060*/0xF5, 0x40, 0xFE, 0xFC, 0xAB, 0x56, 0xFA, 0x12,
+ 0x11, 0x51, 0x7F, 0x0F, 0x7D, 0x18, 0xE4, 0xF5,
+/*1070*/0x56, 0xF5, 0x40, 0xFE, 0xFC, 0xAB, 0x56, 0xFA,
+ 0x12, 0x15, 0x41, 0xAF, 0x56, 0x7E, 0x00, 0x12,
+/*1080*/0x1A, 0xFF, 0xE4, 0xFF, 0xF5, 0x56, 0x7D, 0x1F,
+ 0xF5, 0x40, 0xFE, 0xFC, 0xAB, 0x56, 0xFA, 0x22,
+/*1090*/0x22, 0xE4, 0xF5, 0x55, 0xE5, 0x08, 0xFD, 0x74,
+ 0xA0, 0xF5, 0x56, 0xED, 0x44, 0x07, 0xF5, 0x57,
+/*10A0*/0xE5, 0x28, 0x30, 0xE5, 0x03, 0xD3, 0x80, 0x01,
+ 0xC3, 0x40, 0x05, 0x7F, 0x28, 0xEF, 0x80, 0x04,
+/*10B0*/0x7F, 0x14, 0xEF, 0xC3, 0x13, 0xF5, 0x54, 0xE4,
+ 0xF9, 0x12, 0x0E, 0x18, 0x75, 0x83, 0x8E, 0xE0,
+/*10C0*/0xF5, 0x10, 0xCE, 0xEF, 0xCE, 0xEE, 0xD3, 0x94,
+ 0x00, 0x40, 0x26, 0xE5, 0x10, 0x54, 0xFE, 0x12,
+/*10D0*/0x0E, 0x98, 0x75, 0x83, 0x8E, 0xED, 0xF0, 0xE5,
+ 0x10, 0x44, 0x01, 0xFD, 0xEB, 0x44, 0x07, 0xF5,
+/*10E0*/0x82, 0xED, 0xF0, 0x85, 0x57, 0x82, 0x85, 0x56,
+ 0x83, 0xE0, 0x30, 0xE3, 0x01, 0x09, 0x1E, 0x80,
+/*10F0*/0xD4, 0xC2, 0x34, 0xE9, 0xC3, 0x95, 0x54, 0x40,
+ 0x02, 0xD2, 0x34, 0x22, 0x02, 0x00, 0x06, 0x22,
+/*1100*/0x30, 0x30, 0x11, 0x90, 0x10, 0x00, 0xE4, 0x93,
+ 0xF5, 0x10, 0x90, 0x10, 0x10, 0xE4, 0x93, 0xF5,
+/*1110*/0x10, 0x12, 0x10, 0x90, 0x12, 0x11, 0x50, 0x22,
+ 0xE4, 0xFC, 0xC3, 0xED, 0x9F, 0xFA, 0xEF, 0xF5,
+/*1120*/0x83, 0x75, 0x82, 0x00, 0x79, 0xFF, 0xE4, 0x93,
+ 0xCC, 0x6C, 0xCC, 0xA3, 0xD9, 0xF8, 0xDA, 0xF6,
+/*1130*/0xE5, 0xE2, 0x30, 0xE4, 0x02, 0x8C, 0xE5, 0xED,
+ 0x24, 0xFF, 0xFF, 0xEF, 0x75, 0x82, 0xFF, 0xF5,
+/*1140*/0x83, 0xE4, 0x93, 0x6C, 0x70, 0x03, 0x7F, 0x01,
+ 0x22, 0x7F, 0x00, 0x22, 0x22, 0x11, 0x00, 0x00,
+/*1150*/0x22, 0x8E, 0x58, 0x8F, 0x59, 0x8C, 0x5A, 0x8D,
+ 0x5B, 0x8A, 0x5C, 0x8B, 0x5D, 0x75, 0x5E, 0x01,
+/*1160*/0xE4, 0xF5, 0x5F, 0xF5, 0x60, 0xF5, 0x62, 0x12,
+ 0x07, 0x2A, 0x75, 0x83, 0xD0, 0xE0, 0xFF, 0xC4,
+/*1170*/0x54, 0x0F, 0xF5, 0x61, 0x12, 0x1E, 0xA5, 0x85,
+ 0x59, 0x5E, 0xD3, 0xE5, 0x5E, 0x95, 0x5B, 0xE5,
+/*1180*/0x5A, 0x12, 0x07, 0x6B, 0x50, 0x4B, 0x12, 0x07,
+ 0x03, 0x75, 0x83, 0xBC, 0xE0, 0x45, 0x5E, 0x12,
+/*1190*/0x07, 0x29, 0x75, 0x83, 0xBE, 0xE0, 0x45, 0x5E,
+ 0x12, 0x07, 0x29, 0x75, 0x83, 0xC0, 0xE0, 0x45,
+/*11A0*/0x5E, 0xF0, 0xAF, 0x5F, 0xE5, 0x60, 0x12, 0x08,
+ 0x78, 0x12, 0x0A, 0xFF, 0xAF, 0x62, 0x7E, 0x00,
+/*11B0*/0xAD, 0x5D, 0xAC, 0x5C, 0x12, 0x04, 0x44, 0xE5,
+ 0x61, 0xAF, 0x5E, 0x7E, 0x00, 0xB4, 0x03, 0x05,
+/*11C0*/0x12, 0x1E, 0x21, 0x80, 0x07, 0xAD, 0x5D, 0xAC,
+ 0x5C, 0x12, 0x13, 0x17, 0x05, 0x5E, 0x02, 0x11,
+/*11D0*/0x7A, 0x12, 0x07, 0x03, 0x75, 0x83, 0xBC, 0xE0,
+ 0x45, 0x40, 0x12, 0x07, 0x29, 0x75, 0x83, 0xBE,
+/*11E0*/0xE0, 0x45, 0x40, 0x12, 0x07, 0x29, 0x75, 0x83,
+ 0xC0, 0xE0, 0x45, 0x40, 0xF0, 0x22, 0x8E, 0x58,
+/*11F0*/0x8F, 0x59, 0x75, 0x5A, 0x01, 0x79, 0x01, 0x75,
+ 0x5B, 0x01, 0xE4, 0xFB, 0x12, 0x07, 0x2A, 0x75,
+/*1200*/0x83, 0xAE, 0xE0, 0x54, 0x1A, 0xFF, 0x12, 0x08,
+ 0x65, 0xE0, 0xC4, 0x13, 0x54, 0x07, 0xFE, 0xEF,
+/*1210*/0x70, 0x0C, 0xEE, 0x65, 0x35, 0x70, 0x07, 0x90,
+ 0x07, 0x2F, 0xE0, 0xB4, 0x01, 0x0D, 0xAF, 0x35,
+/*1220*/0x7E, 0x00, 0x12, 0x0E, 0xA9, 0xCF, 0xEB, 0xCF,
+ 0x02, 0x1E, 0x60, 0xE5, 0x59, 0x64, 0x02, 0x45,
+/*1230*/0x58, 0x70, 0x04, 0x7F, 0x01, 0x80, 0x02, 0x7F,
+ 0x00, 0xE5, 0x59, 0x45, 0x58, 0x70, 0x04, 0x7E,
+/*1240*/0x01, 0x80, 0x02, 0x7E, 0x00, 0xEE, 0x4F, 0x60,
+ 0x23, 0x85, 0x41, 0x49, 0x85, 0x40, 0x4B, 0xE5,
+/*1250*/0x59, 0x45, 0x58, 0x70, 0x2C, 0xAF, 0x5A, 0xFE,
+ 0xCD, 0xE9, 0xCD, 0xFC, 0xAB, 0x59, 0xAA, 0x58,
+/*1260*/0x12, 0x0A, 0xFF, 0xAF, 0x5B, 0x7E, 0x00, 0x12,
+ 0x1E, 0x60, 0x80, 0x15, 0xAF, 0x5B, 0x7E, 0x00,
+/*1270*/0x12, 0x1E, 0x60, 0x90, 0x07, 0x26, 0x12, 0x07,
+ 0x35, 0xE5, 0x49, 0x12, 0x07, 0x31, 0xE5, 0x4B,
+/*1280*/0xF0, 0xE4, 0xFD, 0xAF, 0x35, 0xFE, 0xFC, 0x12,
+ 0x09, 0x15, 0x22, 0x8C, 0x64, 0x8D, 0x65, 0x12,
+/*1290*/0x08, 0xDA, 0x40, 0x3C, 0xE5, 0x65, 0x45, 0x64,
+ 0x70, 0x10, 0x12, 0x09, 0x04, 0xC3, 0xE5, 0x3E,
+/*12A0*/0x12, 0x07, 0x69, 0x40, 0x3B, 0x12, 0x08, 0x95,
+ 0x80, 0x18, 0xE5, 0x3E, 0xC3, 0x95, 0x38, 0x40,
+/*12B0*/0x1D, 0x85, 0x3E, 0x38, 0xE5, 0x3E, 0x60, 0x05,
+ 0x85, 0x3F, 0x39, 0x80, 0x03, 0x85, 0x39, 0x39,
+/*12C0*/0x8F, 0x3A, 0x12, 0x07, 0xA8, 0xE5, 0x3E, 0x12,
+ 0x07, 0x53, 0xE5, 0x3F, 0xF0, 0x22, 0x80, 0x3B,
+/*12D0*/0xE5, 0x65, 0x45, 0x64, 0x70, 0x11, 0x12, 0x07,
+ 0x5F, 0x40, 0x05, 0x12, 0x08, 0x9E, 0x80, 0x1F,
+/*12E0*/0x12, 0x07, 0x3E, 0xE5, 0x41, 0xF0, 0x22, 0xE5,
+ 0x3C, 0xC3, 0x95, 0x38, 0x40, 0x1D, 0x85, 0x3C,
+/*12F0*/0x38, 0xE5, 0x3C, 0x60, 0x05, 0x85, 0x3D, 0x39,
+ 0x80, 0x03, 0x85, 0x39, 0x39, 0x8F, 0x3A, 0x12,
+/*1300*/0x07, 0xA8, 0xE5, 0x3C, 0x12, 0x07, 0x53, 0xE5,
+ 0x3D, 0xF0, 0x22, 0x12, 0x07, 0x9F, 0xE5, 0x38,
+/*1310*/0x12, 0x07, 0x53, 0xE5, 0x39, 0xF0, 0x22, 0x8C,
+ 0x63, 0x8D, 0x64, 0x12, 0x08, 0xDA, 0x40, 0x3C,
+/*1320*/0xE5, 0x64, 0x45, 0x63, 0x70, 0x10, 0x12, 0x09,
+ 0x04, 0xC3, 0xE5, 0x3E, 0x12, 0x07, 0x69, 0x40,
+/*1330*/0x3B, 0x12, 0x08, 0x95, 0x80, 0x18, 0xE5, 0x3E,
+ 0xC3, 0x95, 0x38, 0x40, 0x1D, 0x85, 0x3E, 0x38,
+/*1340*/0xE5, 0x3E, 0x60, 0x05, 0x85, 0x3F, 0x39, 0x80,
+ 0x03, 0x85, 0x39, 0x39, 0x8F, 0x3A, 0x12, 0x07,
+/*1350*/0xA8, 0xE5, 0x3E, 0x12, 0x07, 0x53, 0xE5, 0x3F,
+ 0xF0, 0x22, 0x80, 0x3B, 0xE5, 0x64, 0x45, 0x63,
+/*1360*/0x70, 0x11, 0x12, 0x07, 0x5F, 0x40, 0x05, 0x12,
+ 0x08, 0x9E, 0x80, 0x1F, 0x12, 0x07, 0x3E, 0xE5,
+/*1370*/0x41, 0xF0, 0x22, 0xE5, 0x3C, 0xC3, 0x95, 0x38,
+ 0x40, 0x1D, 0x85, 0x3C, 0x38, 0xE5, 0x3C, 0x60,
+/*1380*/0x05, 0x85, 0x3D, 0x39, 0x80, 0x03, 0x85, 0x39,
+ 0x39, 0x8F, 0x3A, 0x12, 0x07, 0xA8, 0xE5, 0x3C,
+/*1390*/0x12, 0x07, 0x53, 0xE5, 0x3D, 0xF0, 0x22, 0x12,
+ 0x07, 0x9F, 0xE5, 0x38, 0x12, 0x07, 0x53, 0xE5,
+/*13A0*/0x39, 0xF0, 0x22, 0xE5, 0x0D, 0xFE, 0xE5, 0x08,
+ 0x8E, 0x54, 0x44, 0x05, 0xF5, 0x55, 0x75, 0x15,
+/*13B0*/0x0F, 0xF5, 0x82, 0x12, 0x0E, 0x7A, 0x12, 0x17,
+ 0xA3, 0x20, 0x31, 0x05, 0x75, 0x15, 0x03, 0x80,
+/*13C0*/0x03, 0x75, 0x15, 0x0B, 0xE5, 0x0A, 0xC3, 0x94,
+ 0x01, 0x50, 0x38, 0x12, 0x14, 0x20, 0x20, 0x31,
+/*13D0*/0x06, 0x05, 0x15, 0x05, 0x15, 0x80, 0x04, 0x15,
+ 0x15, 0x15, 0x15, 0xE5, 0x0A, 0xC3, 0x94, 0x01,
+/*13E0*/0x50, 0x21, 0x12, 0x14, 0x20, 0x20, 0x31, 0x04,
+ 0x05, 0x15, 0x80, 0x02, 0x15, 0x15, 0xE5, 0x0A,
+/*13F0*/0xC3, 0x94, 0x01, 0x50, 0x0E, 0x12, 0x0E, 0x77,
+ 0x12, 0x17, 0xA3, 0x20, 0x31, 0x05, 0x05, 0x15,
+/*1400*/0x12, 0x0E, 0x77, 0xE5, 0x15, 0xB4, 0x08, 0x04,
+ 0x7F, 0x01, 0x80, 0x02, 0x7F, 0x00, 0xE5, 0x15,
+/*1410*/0xB4, 0x07, 0x04, 0x7E, 0x01, 0x80, 0x02, 0x7E,
+ 0x00, 0xEE, 0x4F, 0x60, 0x02, 0x05, 0x7F, 0x22,
+/*1420*/0x85, 0x55, 0x82, 0x85, 0x54, 0x83, 0xE5, 0x15,
+ 0xF0, 0x12, 0x17, 0xA3, 0x22, 0x12, 0x07, 0x2A,
+/*1430*/0x75, 0x83, 0xAE, 0x74, 0xFF, 0x12, 0x07, 0x29,
+ 0xE0, 0x54, 0x1A, 0xF5, 0x34, 0xE0, 0xC4, 0x13,
+/*1440*/0x54, 0x07, 0xF5, 0x35, 0x24, 0xFE, 0x60, 0x24,
+ 0x24, 0xFE, 0x60, 0x3C, 0x24, 0x04, 0x70, 0x63,
+/*1450*/0x75, 0x31, 0x2D, 0xE5, 0x08, 0xFD, 0x74, 0xB6,
+ 0x12, 0x07, 0x92, 0x74, 0xBC, 0x90, 0x07, 0x22,
+/*1460*/0x12, 0x07, 0x95, 0x74, 0x90, 0x12, 0x07, 0xB3,
+ 0x74, 0x92, 0x80, 0x3C, 0x75, 0x31, 0x3A, 0xE5,
+/*1470*/0x08, 0xFD, 0x74, 0xBA, 0x12, 0x07, 0x92, 0x74,
+ 0xC0, 0x90, 0x07, 0x22, 0x12, 0x07, 0xB6, 0x74,
+/*1480*/0xC4, 0x12, 0x07, 0xB3, 0x74, 0xC8, 0x80, 0x20,
+ 0x75, 0x31, 0x35, 0xE5, 0x08, 0xFD, 0x74, 0xB8,
+/*1490*/0x12, 0x07, 0x92, 0x74, 0xBE, 0xFF, 0xED, 0x44,
+ 0x07, 0x90, 0x07, 0x22, 0xCF, 0xF0, 0xA3, 0xEF,
+/*14A0*/0xF0, 0x74, 0xC2, 0x12, 0x07, 0xB3, 0x74, 0xC6,
+ 0xFF, 0xED, 0x44, 0x07, 0xA3, 0xCF, 0xF0, 0xA3,
+/*14B0*/0xEF, 0xF0, 0x22, 0x75, 0x34, 0x01, 0x22, 0x8E,
+ 0x58, 0x8F, 0x59, 0x8C, 0x5A, 0x8D, 0x5B, 0x8A,
+/*14C0*/0x5C, 0x8B, 0x5D, 0x75, 0x5E, 0x01, 0xE4, 0xF5,
+ 0x5F, 0x12, 0x1E, 0xA5, 0x85, 0x59, 0x5E, 0xD3,
+/*14D0*/0xE5, 0x5E, 0x95, 0x5B, 0xE5, 0x5A, 0x12, 0x07,
+ 0x6B, 0x50, 0x57, 0xE5, 0x5D, 0x45, 0x5C, 0x70,
+/*14E0*/0x30, 0x12, 0x07, 0x2A, 0x75, 0x83, 0x92, 0xE5,
+ 0x5E, 0x12, 0x07, 0x29, 0x75, 0x83, 0xC6, 0xE5,
+/*14F0*/0x5E, 0x12, 0x07, 0x29, 0x75, 0x83, 0xC8, 0xE5,
+ 0x5E, 0x12, 0x07, 0x29, 0x75, 0x83, 0x90, 0xE5,
+/*1500*/0x5E, 0x12, 0x07, 0x29, 0x75, 0x83, 0xC2, 0xE5,
+ 0x5E, 0x12, 0x07, 0x29, 0x75, 0x83, 0xC4, 0x80,
+/*1510*/0x03, 0x12, 0x07, 0x32, 0xE5, 0x5E, 0xF0, 0xAF,
+ 0x5F, 0x7E, 0x00, 0xAD, 0x5D, 0xAC, 0x5C, 0x12,
+/*1520*/0x04, 0x44, 0xAF, 0x5E, 0x7E, 0x00, 0xAD, 0x5D,
+ 0xAC, 0x5C, 0x12, 0x0B, 0xD1, 0x05, 0x5E, 0x02,
+/*1530*/0x14, 0xCF, 0xAB, 0x5D, 0xAA, 0x5C, 0xAD, 0x5B,
+ 0xAC, 0x5A, 0xAF, 0x59, 0xAE, 0x58, 0x02, 0x1B,
+/*1540*/0xFB, 0x8C, 0x5C, 0x8D, 0x5D, 0x8A, 0x5E, 0x8B,
+ 0x5F, 0x75, 0x60, 0x01, 0xE4, 0xF5, 0x61, 0xF5,
+/*1550*/0x62, 0xF5, 0x63, 0x12, 0x1E, 0xA5, 0x8F, 0x60,
+ 0xD3, 0xE5, 0x60, 0x95, 0x5D, 0xE5, 0x5C, 0x12,
+/*1560*/0x07, 0x6B, 0x50, 0x61, 0xE5, 0x5F, 0x45, 0x5E,
+ 0x70, 0x27, 0x12, 0x07, 0x2A, 0x75, 0x83, 0xB6,
+/*1570*/0xE5, 0x60, 0x12, 0x07, 0x29, 0x75, 0x83, 0xB8,
+ 0xE5, 0x60, 0x12, 0x07, 0x29, 0x75, 0x83, 0xBA,
+/*1580*/0xE5, 0x60, 0xF0, 0xAF, 0x61, 0x7E, 0x00, 0xE5,
+ 0x62, 0x12, 0x08, 0x7A, 0x12, 0x0A, 0xFF, 0x80,
+/*1590*/0x19, 0x90, 0x07, 0x24, 0x12, 0x07, 0x35, 0xE5,
+ 0x60, 0x12, 0x07, 0x29, 0x75, 0x83, 0x8E, 0xE4,
+/*15A0*/0x12, 0x07, 0x29, 0x74, 0x01, 0x12, 0x07, 0x29,
+ 0xE4, 0xF0, 0xAF, 0x63, 0x7E, 0x00, 0xAD, 0x5F,
+/*15B0*/0xAC, 0x5E, 0x12, 0x04, 0x44, 0xAF, 0x60, 0x7E,
+ 0x00, 0xAD, 0x5F, 0xAC, 0x5E, 0x12, 0x12, 0x8B,
+/*15C0*/0x05, 0x60, 0x02, 0x15, 0x58, 0x22, 0x90, 0x11,
+ 0x4D, 0xE4, 0x93, 0x90, 0x07, 0x2E, 0xF0, 0x12,
+/*15D0*/0x08, 0x1F, 0x75, 0x83, 0xAE, 0xE0, 0x54, 0x1A,
+ 0xF5, 0x34, 0x70, 0x67, 0xEF, 0x44, 0x07, 0xF5,
+/*15E0*/0x82, 0x75, 0x83, 0xCE, 0xE0, 0xFF, 0x13, 0x13,
+ 0x13, 0x54, 0x07, 0xF5, 0x36, 0x54, 0x0F, 0xD3,
+/*15F0*/0x94, 0x00, 0x40, 0x06, 0x12, 0x14, 0x2D, 0x12,
+ 0x1B, 0xA9, 0xE5, 0x36, 0x54, 0x0F, 0x24, 0xFE,
+/*1600*/0x60, 0x0C, 0x14, 0x60, 0x0C, 0x14, 0x60, 0x19,
+ 0x24, 0x03, 0x70, 0x37, 0x80, 0x10, 0x02, 0x1E,
+/*1610*/0x91, 0x12, 0x1E, 0x91, 0x12, 0x07, 0x2A, 0x75,
+ 0x83, 0xCE, 0xE0, 0x54, 0xEF, 0xF0, 0x02, 0x1D,
+/*1620*/0xAE, 0x12, 0x10, 0x14, 0xE4, 0xF5, 0x55, 0x12,
+ 0x1D, 0x85, 0x05, 0x55, 0xE5, 0x55, 0xC3, 0x94,
+/*1630*/0x05, 0x40, 0xF4, 0x12, 0x07, 0x2A, 0x75, 0x83,
+ 0xCE, 0xE0, 0x54, 0xC7, 0x12, 0x07, 0x29, 0xE0,
+/*1640*/0x44, 0x08, 0xF0, 0x22, 0xE4, 0xF5, 0x58, 0xF5,
+ 0x59, 0xAF, 0x08, 0xEF, 0x44, 0x07, 0xF5, 0x82,
+/*1650*/0x75, 0x83, 0xD0, 0xE0, 0xFD, 0xC4, 0x54, 0x0F,
+ 0xF5, 0x5A, 0xEF, 0x44, 0x07, 0xF5, 0x82, 0x75,
+/*1660*/0x83, 0x80, 0x74, 0x01, 0xF0, 0x12, 0x08, 0x21,
+ 0x75, 0x83, 0x82, 0xE5, 0x45, 0xF0, 0xEF, 0x44,
+/*1670*/0x07, 0xF5, 0x82, 0x75, 0x83, 0x8A, 0x74, 0xFF,
+ 0xF0, 0x12, 0x1A, 0x4D, 0x12, 0x07, 0x2A, 0x75,
+/*1680*/0x83, 0xBC, 0xE0, 0x54, 0xEF, 0x12, 0x07, 0x29,
+ 0x75, 0x83, 0xBE, 0xE0, 0x54, 0xEF, 0x12, 0x07,
+/*1690*/0x29, 0x75, 0x83, 0xC0, 0xE0, 0x54, 0xEF, 0x12,
+ 0x07, 0x29, 0x75, 0x83, 0xBC, 0xE0, 0x44, 0x10,
+/*16A0*/0x12, 0x07, 0x29, 0x75, 0x83, 0xBE, 0xE0, 0x44,
+ 0x10, 0x12, 0x07, 0x29, 0x75, 0x83, 0xC0, 0xE0,
+/*16B0*/0x44, 0x10, 0xF0, 0xAF, 0x58, 0xE5, 0x59, 0x12,
+ 0x08, 0x78, 0x02, 0x0A, 0xFF, 0xE4, 0xF5, 0x58,
+/*16C0*/0x7D, 0x01, 0xF5, 0x59, 0xAF, 0x35, 0xFE, 0xFC,
+ 0x12, 0x09, 0x15, 0x12, 0x07, 0x2A, 0x75, 0x83,
+/*16D0*/0xB6, 0x74, 0x10, 0x12, 0x07, 0x29, 0x75, 0x83,
+ 0xB8, 0x74, 0x10, 0x12, 0x07, 0x29, 0x75, 0x83,
+/*16E0*/0xBA, 0x74, 0x10, 0x12, 0x07, 0x29, 0x75, 0x83,
+ 0xBC, 0x74, 0x10, 0x12, 0x07, 0x29, 0x75, 0x83,
+/*16F0*/0xBE, 0x74, 0x10, 0x12, 0x07, 0x29, 0x75, 0x83,
+ 0xC0, 0x74, 0x10, 0x12, 0x07, 0x29, 0x75, 0x83,
+/*1700*/0x90, 0xE4, 0x12, 0x07, 0x29, 0x75, 0x83, 0xC2,
+ 0xE4, 0x12, 0x07, 0x29, 0x75, 0x83, 0xC4, 0xE4,
+/*1710*/0x12, 0x07, 0x29, 0x75, 0x83, 0x92, 0xE4, 0x12,
+ 0x07, 0x29, 0x75, 0x83, 0xC6, 0xE4, 0x12, 0x07,
+/*1720*/0x29, 0x75, 0x83, 0xC8, 0xE4, 0xF0, 0xAF, 0x58,
+ 0xFE, 0xE5, 0x59, 0x12, 0x08, 0x7A, 0x02, 0x0A,
+/*1730*/0xFF, 0xE5, 0xE2, 0x30, 0xE4, 0x6C, 0xE5, 0xE7,
+ 0x54, 0xC0, 0x64, 0x40, 0x70, 0x64, 0xE5, 0x09,
+/*1740*/0xC4, 0x54, 0x30, 0xFE, 0xE5, 0x08, 0x25, 0xE0,
+ 0x25, 0xE0, 0x54, 0xC0, 0x4E, 0xFE, 0xEF, 0x54,
+/*1750*/0x3F, 0x4E, 0xFD, 0xE5, 0x2B, 0xAE, 0x2A, 0x78,
+ 0x02, 0xC3, 0x33, 0xCE, 0x33, 0xCE, 0xD8, 0xF9,
+/*1760*/0xF5, 0x82, 0x8E, 0x83, 0xED, 0xF0, 0xE5, 0x2B,
+ 0xAE, 0x2A, 0x78, 0x02, 0xC3, 0x33, 0xCE, 0x33,
+/*1770*/0xCE, 0xD8, 0xF9, 0xFF, 0xF5, 0x82, 0x8E, 0x83,
+ 0xA3, 0xE5, 0xFE, 0xF0, 0x8F, 0x82, 0x8E, 0x83,
+/*1780*/0xA3, 0xA3, 0xE5, 0xFD, 0xF0, 0x8F, 0x82, 0x8E,
+ 0x83, 0xA3, 0xA3, 0xA3, 0xE5, 0xFC, 0xF0, 0xC3,
+/*1790*/0xE5, 0x2B, 0x94, 0xFA, 0xE5, 0x2A, 0x94, 0x00,
+ 0x50, 0x08, 0x05, 0x2B, 0xE5, 0x2B, 0x70, 0x02,
+/*17A0*/0x05, 0x2A, 0x22, 0xE4, 0xFF, 0xE4, 0xF5, 0x58,
+ 0xF5, 0x56, 0xF5, 0x57, 0x74, 0x82, 0xFC, 0x12,
+/*17B0*/0x0E, 0x04, 0x8C, 0x83, 0xE0, 0xF5, 0x10, 0x54,
+ 0x7F, 0xF0, 0xE5, 0x10, 0x44, 0x80, 0x12, 0x0E,
+/*17C0*/0x98, 0xED, 0xF0, 0x7E, 0x0A, 0x12, 0x0E, 0x04,
+ 0x75, 0x83, 0xA0, 0xE0, 0x20, 0xE0, 0x26, 0xDE,
+/*17D0*/0xF4, 0x05, 0x57, 0xE5, 0x57, 0x70, 0x02, 0x05,
+ 0x56, 0xE5, 0x14, 0x24, 0x01, 0xFD, 0xE4, 0x33,
+/*17E0*/0xFC, 0xD3, 0xE5, 0x57, 0x9D, 0xE5, 0x56, 0x9C,
+ 0x40, 0xD9, 0xE5, 0x0A, 0x94, 0x20, 0x50, 0x02,
+/*17F0*/0x05, 0x0A, 0x43, 0xE1, 0x08, 0xC2, 0x31, 0x12,
+ 0x0E, 0x04, 0x75, 0x83, 0xA6, 0xE0, 0x55, 0x12,
+/*1800*/0x65, 0x12, 0x70, 0x03, 0xD2, 0x31, 0x22, 0xC2,
+ 0x31, 0x22, 0x90, 0x07, 0x26, 0xE0, 0xFA, 0xA3,
+/*1810*/0xE0, 0xF5, 0x82, 0x8A, 0x83, 0xE0, 0xF5, 0x41,
+ 0xE5, 0x39, 0xC3, 0x95, 0x41, 0x40, 0x26, 0xE5,
+/*1820*/0x39, 0x95, 0x41, 0xC3, 0x9F, 0xEE, 0x12, 0x07,
+ 0x6B, 0x40, 0x04, 0x7C, 0x01, 0x80, 0x02, 0x7C,
+/*1830*/0x00, 0xE5, 0x41, 0x64, 0x3F, 0x60, 0x04, 0x7B,
+ 0x01, 0x80, 0x02, 0x7B, 0x00, 0xEC, 0x5B, 0x60,
+/*1840*/0x29, 0x05, 0x41, 0x80, 0x28, 0xC3, 0xE5, 0x41,
+ 0x95, 0x39, 0xC3, 0x9F, 0xEE, 0x12, 0x07, 0x6B,
+/*1850*/0x40, 0x04, 0x7F, 0x01, 0x80, 0x02, 0x7F, 0x00,
+ 0xE5, 0x41, 0x60, 0x04, 0x7E, 0x01, 0x80, 0x02,
+/*1860*/0x7E, 0x00, 0xEF, 0x5E, 0x60, 0x04, 0x15, 0x41,
+ 0x80, 0x03, 0x85, 0x39, 0x41, 0x85, 0x3A, 0x40,
+/*1870*/0x22, 0xE5, 0xE2, 0x30, 0xE4, 0x60, 0xE5, 0xE1,
+ 0x30, 0xE2, 0x5B, 0xE5, 0x09, 0x70, 0x04, 0x7F,
+/*1880*/0x01, 0x80, 0x02, 0x7F, 0x00, 0xE5, 0x08, 0x70,
+ 0x04, 0x7E, 0x01, 0x80, 0x02, 0x7E, 0x00, 0xEE,
+/*1890*/0x5F, 0x60, 0x43, 0x53, 0xF9, 0xF8, 0xE5, 0xE2,
+ 0x30, 0xE4, 0x3B, 0xE5, 0xE1, 0x30, 0xE2, 0x2E,
+/*18A0*/0x43, 0xFA, 0x02, 0x53, 0xFA, 0xFB, 0xE4, 0xF5,
+ 0x10, 0x90, 0x94, 0x70, 0xE5, 0x10, 0xF0, 0xE5,
+/*18B0*/0xE1, 0x30, 0xE2, 0xE7, 0x90, 0x94, 0x70, 0xE0,
+ 0x65, 0x10, 0x60, 0x03, 0x43, 0xFA, 0x04, 0x05,
+/*18C0*/0x10, 0x90, 0x94, 0x70, 0xE5, 0x10, 0xF0, 0x70,
+ 0xE6, 0x12, 0x00, 0x06, 0x80, 0xE1, 0x53, 0xFA,
+/*18D0*/0xFD, 0x53, 0xFA, 0xFB, 0x80, 0xC0, 0x22, 0x8F,
+ 0x54, 0x12, 0x00, 0x06, 0xE5, 0xE1, 0x30, 0xE0,
+/*18E0*/0x04, 0x7F, 0x01, 0x80, 0x02, 0x7F, 0x00, 0xE5,
+ 0x7E, 0xD3, 0x94, 0x05, 0x40, 0x04, 0x7E, 0x01,
+/*18F0*/0x80, 0x02, 0x7E, 0x00, 0xEE, 0x4F, 0x60, 0x3D,
+ 0x85, 0x54, 0x11, 0xE5, 0xE2, 0x20, 0xE1, 0x32,
+/*1900*/0x74, 0xCE, 0x12, 0x1A, 0x05, 0x30, 0xE7, 0x04,
+ 0x7D, 0x01, 0x80, 0x02, 0x7D, 0x00, 0x8F, 0x82,
+/*1910*/0x8E, 0x83, 0xE0, 0x30, 0xE6, 0x04, 0x7F, 0x01,
+ 0x80, 0x02, 0x7F, 0x00, 0xEF, 0x5D, 0x70, 0x15,
+/*1920*/0x12, 0x15, 0xC6, 0x74, 0xCE, 0x12, 0x1A, 0x05,
+ 0x30, 0xE6, 0x07, 0xE0, 0x44, 0x80, 0xF0, 0x43,
+/*1930*/0xF9, 0x80, 0x12, 0x18, 0x71, 0x22, 0x12, 0x0E,
+ 0x44, 0xE5, 0x16, 0x25, 0xE0, 0x25, 0xE0, 0x24,
+/*1940*/0xB0, 0xF5, 0x82, 0xE4, 0x34, 0x1A, 0xF5, 0x83,
+ 0xE4, 0x93, 0xF5, 0x0F, 0xE5, 0x16, 0x25, 0xE0,
+/*1950*/0x25, 0xE0, 0x24, 0xB1, 0xF5, 0x82, 0xE4, 0x34,
+ 0x1A, 0xF5, 0x83, 0xE4, 0x93, 0xF5, 0x0E, 0x12,
+/*1960*/0x0E, 0x65, 0xF5, 0x10, 0xE5, 0x0F, 0x54, 0xF0,
+ 0x12, 0x0E, 0x17, 0x75, 0x83, 0x8C, 0xEF, 0xF0,
+/*1970*/0xE5, 0x0F, 0x30, 0xE0, 0x0C, 0x12, 0x0E, 0x04,
+ 0x75, 0x83, 0x86, 0xE0, 0x44, 0x40, 0xF0, 0x80,
+/*1980*/0x0A, 0x12, 0x0E, 0x04, 0x75, 0x83, 0x86, 0xE0,
+ 0x54, 0xBF, 0xF0, 0x12, 0x0E, 0x91, 0x75, 0x83,
+/*1990*/0x82, 0xE5, 0x0E, 0xF0, 0x22, 0x7F, 0x05, 0x12,
+ 0x17, 0x31, 0x12, 0x0E, 0x04, 0x12, 0x0E, 0x33,
+/*19A0*/0x74, 0x02, 0xF0, 0x74, 0x8E, 0xFE, 0x12, 0x0E,
+ 0x04, 0x12, 0x0E, 0x0B, 0xEF, 0xF0, 0x75, 0x15,
+/*19B0*/0x70, 0x12, 0x0F, 0xF7, 0x20, 0x34, 0x05, 0x75,
+ 0x15, 0x10, 0x80, 0x03, 0x75, 0x15, 0x50, 0x12,
+/*19C0*/0x0F, 0xF7, 0x20, 0x34, 0x04, 0x74, 0x10, 0x80,
+ 0x02, 0x74, 0xF0, 0x25, 0x15, 0xF5, 0x15, 0x12,
+/*19D0*/0x0E, 0x21, 0xEF, 0xF0, 0x12, 0x10, 0x91, 0x20,
+ 0x34, 0x17, 0xE5, 0x15, 0x64, 0x30, 0x60, 0x0C,
+/*19E0*/0x74, 0x10, 0x25, 0x15, 0xF5, 0x15, 0xB4, 0x80,
+ 0x03, 0xE4, 0xF5, 0x15, 0x12, 0x0E, 0x21, 0xEF,
+/*19F0*/0xF0, 0x22, 0xF0, 0xE5, 0x0B, 0x25, 0xE0, 0x25,
+ 0xE0, 0x24, 0x82, 0xF5, 0x82, 0xE4, 0x34, 0x07,
+/*1A00*/0xF5, 0x83, 0x22, 0x74, 0x88, 0xFE, 0xE5, 0x08,
+ 0x44, 0x07, 0xFF, 0xF5, 0x82, 0x8E, 0x83, 0xE0,
+/*1A10*/0x22, 0xF0, 0xE5, 0x08, 0x44, 0x07, 0xF5, 0x82,
+ 0x22, 0xF0, 0xE0, 0x54, 0xC0, 0x8F, 0x82, 0x8E,
+/*1A20*/0x83, 0xF0, 0x22, 0xEF, 0x44, 0x07, 0xF5, 0x82,
+ 0x75, 0x83, 0x86, 0xE0, 0x54, 0x10, 0xD3, 0x94,
+/*1A30*/0x00, 0x22, 0xF0, 0x90, 0x07, 0x15, 0xE0, 0x04,
+ 0xF0, 0x22, 0x44, 0x06, 0xF5, 0x82, 0x75, 0x83,
+/*1A40*/0x9E, 0xE0, 0x22, 0xFE, 0xEF, 0x44, 0x07, 0xF5,
+ 0x82, 0x8E, 0x83, 0xE0, 0x22, 0xE4, 0x90, 0x07,
+/*1A50*/0x2A, 0xF0, 0xA3, 0xF0, 0x12, 0x07, 0x2A, 0x75,
+ 0x83, 0x82, 0xE0, 0x54, 0x7F, 0x12, 0x07, 0x29,
+/*1A60*/0xE0, 0x44, 0x80, 0xF0, 0x12, 0x10, 0xFC, 0x12,
+ 0x08, 0x1F, 0x75, 0x83, 0xA0, 0xE0, 0x20, 0xE0,
+/*1A70*/0x1A, 0x90, 0x07, 0x2B, 0xE0, 0x04, 0xF0, 0x70,
+ 0x06, 0x90, 0x07, 0x2A, 0xE0, 0x04, 0xF0, 0x90,
+/*1A80*/0x07, 0x2A, 0xE0, 0xB4, 0x10, 0xE1, 0xA3, 0xE0,
+ 0xB4, 0x00, 0xDC, 0xEE, 0x44, 0xA6, 0xFC, 0xEF,
+/*1A90*/0x44, 0x07, 0xF5, 0x82, 0x8C, 0x83, 0xE0, 0xF5,
+ 0x32, 0xEE, 0x44, 0xA8, 0xFE, 0xEF, 0x44, 0x07,
+/*1AA0*/0xF5, 0x82, 0x8E, 0x83, 0xE0, 0xF5, 0x33, 0x22,
+ 0x01, 0x20, 0x11, 0x00, 0x04, 0x20, 0x00, 0x90,
+/*1AB0*/0x00, 0x20, 0x0F, 0x92, 0x00, 0x21, 0x0F, 0x94,
+ 0x00, 0x22, 0x0F, 0x96, 0x00, 0x23, 0x0F, 0x98,
+/*1AC0*/0x00, 0x24, 0x0F, 0x9A, 0x00, 0x25, 0x0F, 0x9C,
+ 0x00, 0x26, 0x0F, 0x9E, 0x00, 0x27, 0x0F, 0xA0,
+/*1AD0*/0x01, 0x20, 0x01, 0xA2, 0x01, 0x21, 0x01, 0xA4,
+ 0x01, 0x22, 0x01, 0xA6, 0x01, 0x23, 0x01, 0xA8,
+/*1AE0*/0x01, 0x24, 0x01, 0xAA, 0x01, 0x25, 0x01, 0xAC,
+ 0x01, 0x26, 0x01, 0xAE, 0x01, 0x27, 0x01, 0xB0,
+/*1AF0*/0x01, 0x28, 0x01, 0xB4, 0x00, 0x28, 0x0F, 0xB6,
+ 0x40, 0x28, 0x0F, 0xB8, 0x61, 0x28, 0x01, 0xCB,
+/*1B00*/0xEF, 0xCB, 0xCA, 0xEE, 0xCA, 0x7F, 0x01, 0xE4,
+ 0xFD, 0xEB, 0x4A, 0x70, 0x24, 0xE5, 0x08, 0xF5,
+/*1B10*/0x82, 0x74, 0xB6, 0x12, 0x08, 0x29, 0xE5, 0x08,
+ 0xF5, 0x82, 0x74, 0xB8, 0x12, 0x08, 0x29, 0xE5,
+/*1B20*/0x08, 0xF5, 0x82, 0x74, 0xBA, 0x12, 0x08, 0x29,
+ 0x7E, 0x00, 0x7C, 0x00, 0x12, 0x0A, 0xFF, 0x80,
+/*1B30*/0x12, 0x90, 0x07, 0x26, 0x12, 0x07, 0x35, 0xE5,
+ 0x41, 0xF0, 0x90, 0x07, 0x24, 0x12, 0x07, 0x35,
+/*1B40*/0xE5, 0x40, 0xF0, 0x12, 0x07, 0x2A, 0x75, 0x83,
+ 0x8E, 0xE4, 0x12, 0x07, 0x29, 0x74, 0x01, 0x12,
+/*1B50*/0x07, 0x29, 0xE4, 0xF0, 0x22, 0xE4, 0xF5, 0x26,
+ 0xF5, 0x27, 0x53, 0xE1, 0xFE, 0xF5, 0x2A, 0x75,
+/*1B60*/0x2B, 0x01, 0xF5, 0x08, 0x7F, 0x01, 0x12, 0x17,
+ 0x31, 0x30, 0x30, 0x1C, 0x90, 0x1A, 0xA9, 0xE4,
+/*1B70*/0x93, 0xF5, 0x10, 0x90, 0x1F, 0xF9, 0xE4, 0x93,
+ 0xF5, 0x10, 0x90, 0x00, 0x41, 0xE4, 0x93, 0xF5,
+/*1B80*/0x10, 0x90, 0x1E, 0xCA, 0xE4, 0x93, 0xF5, 0x10,
+ 0x7F, 0x02, 0x12, 0x17, 0x31, 0x12, 0x0F, 0x54,
+/*1B90*/0x7F, 0x03, 0x12, 0x17, 0x31, 0x12, 0x00, 0x06,
+ 0xE5, 0xE2, 0x30, 0xE7, 0x09, 0x12, 0x10, 0x00,
+/*1BA0*/0x30, 0x30, 0x03, 0x12, 0x11, 0x00, 0x02, 0x00,
+ 0x47, 0x12, 0x08, 0x1F, 0x75, 0x83, 0xD0, 0xE0,
+/*1BB0*/0xC4, 0x54, 0x0F, 0xFD, 0x75, 0x43, 0x01, 0x75,
+ 0x44, 0xFF, 0x12, 0x08, 0xAA, 0x74, 0x04, 0xF0,
+/*1BC0*/0x75, 0x3B, 0x01, 0xED, 0x14, 0x60, 0x0C, 0x14,
+ 0x60, 0x0B, 0x14, 0x60, 0x0F, 0x24, 0x03, 0x70,
+/*1BD0*/0x0B, 0x80, 0x09, 0x80, 0x00, 0x12, 0x08, 0xA7,
+ 0x04, 0xF0, 0x80, 0x06, 0x12, 0x08, 0xA7, 0x74,
+/*1BE0*/0x04, 0xF0, 0xEE, 0x44, 0x82, 0xFE, 0xEF, 0x44,
+ 0x07, 0xF5, 0x82, 0x8E, 0x83, 0xE5, 0x45, 0x12,
+/*1BF0*/0x08, 0xBE, 0x75, 0x83, 0x82, 0xE5, 0x31, 0xF0,
+ 0x02, 0x11, 0x4C, 0x8E, 0x60, 0x8F, 0x61, 0x12,
+/*1C00*/0x1E, 0xA5, 0xE4, 0xFF, 0xCE, 0xED, 0xCE, 0xEE,
+ 0xD3, 0x95, 0x61, 0xE5, 0x60, 0x12, 0x07, 0x6B,
+/*1C10*/0x40, 0x39, 0x74, 0x20, 0x2E, 0xF5, 0x82, 0xE4,
+ 0x34, 0x03, 0xF5, 0x83, 0xE0, 0x70, 0x03, 0xFF,
+/*1C20*/0x80, 0x26, 0x12, 0x08, 0xE2, 0xFD, 0xC3, 0x9F,
+ 0x40, 0x1E, 0xCF, 0xED, 0xCF, 0xEB, 0x4A, 0x70,
+/*1C30*/0x0B, 0x8D, 0x42, 0x12, 0x08, 0xEE, 0xF5, 0x41,
+ 0x8E, 0x40, 0x80, 0x0C, 0x12, 0x08, 0xE2, 0xF5,
+/*1C40*/0x38, 0x12, 0x08, 0xEE, 0xF5, 0x39, 0x8E, 0x3A,
+ 0x1E, 0x80, 0xBC, 0x22, 0x75, 0x58, 0x01, 0xE5,
+/*1C50*/0x35, 0x70, 0x0C, 0x12, 0x07, 0xCC, 0xE0, 0xF5,
+ 0x4A, 0x12, 0x07, 0xD8, 0xE0, 0xF5, 0x4C, 0xE5,
+/*1C60*/0x35, 0xB4, 0x04, 0x0C, 0x12, 0x07, 0xE4, 0xE0,
+ 0xF5, 0x4A, 0x12, 0x07, 0xF0, 0xE0, 0xF5, 0x4C,
+/*1C70*/0xE5, 0x35, 0xB4, 0x01, 0x04, 0x7F, 0x01, 0x80,
+ 0x02, 0x7F, 0x00, 0xE5, 0x35, 0xB4, 0x02, 0x04,
+/*1C80*/0x7E, 0x01, 0x80, 0x02, 0x7E, 0x00, 0xEE, 0x4F,
+ 0x60, 0x0C, 0x12, 0x07, 0xFC, 0xE0, 0xF5, 0x4A,
+/*1C90*/0x12, 0x08, 0x08, 0xE0, 0xF5, 0x4C, 0x85, 0x41,
+ 0x49, 0x85, 0x40, 0x4B, 0x22, 0x75, 0x5B, 0x01,
+/*1CA0*/0x90, 0x07, 0x24, 0x12, 0x07, 0x35, 0xE0, 0x54,
+ 0x1F, 0xFF, 0xD3, 0x94, 0x02, 0x50, 0x04, 0x8F,
+/*1CB0*/0x58, 0x80, 0x05, 0xEF, 0x24, 0xFE, 0xF5, 0x58,
+ 0xEF, 0xC3, 0x94, 0x18, 0x40, 0x05, 0x75, 0x59,
+/*1CC0*/0x18, 0x80, 0x04, 0xEF, 0x04, 0xF5, 0x59, 0x85,
+ 0x43, 0x5A, 0xAF, 0x58, 0x7E, 0x00, 0xAD, 0x59,
+/*1CD0*/0x7C, 0x00, 0xAB, 0x5B, 0x7A, 0x00, 0x12, 0x15,
+ 0x41, 0xAF, 0x5A, 0x7E, 0x00, 0x12, 0x18, 0x0A,
+/*1CE0*/0xAF, 0x5B, 0x7E, 0x00, 0x02, 0x1A, 0xFF, 0xE5,
+ 0xE2, 0x30, 0xE7, 0x0E, 0x12, 0x10, 0x03, 0xC2,
+/*1CF0*/0x30, 0x30, 0x30, 0x03, 0x12, 0x10, 0xFF, 0x20,
+ 0x33, 0x28, 0xE5, 0xE7, 0x30, 0xE7, 0x05, 0x12,
+/*1D00*/0x0E, 0xA2, 0x80, 0x0D, 0xE5, 0xFE, 0xC3, 0x94,
+ 0x20, 0x50, 0x06, 0x12, 0x0E, 0xA2, 0x43, 0xF9,
+/*1D10*/0x08, 0xE5, 0xF2, 0x30, 0xE7, 0x03, 0x53, 0xF9,
+ 0x7F, 0xE5, 0xF1, 0x54, 0x70, 0xD3, 0x94, 0x00,
+/*1D20*/0x50, 0xD8, 0x22, 0x12, 0x0E, 0x04, 0x75, 0x83,
+ 0x80, 0xE4, 0xF0, 0xE5, 0x08, 0x44, 0x07, 0x12,
+/*1D30*/0x0D, 0xFD, 0x75, 0x83, 0x84, 0x12, 0x0E, 0x02,
+ 0x75, 0x83, 0x86, 0x12, 0x0E, 0x02, 0x75, 0x83,
+/*1D40*/0x8C, 0xE0, 0x54, 0xF3, 0x12, 0x0E, 0x03, 0x75,
+ 0x83, 0x8E, 0x12, 0x0E, 0x02, 0x75, 0x83, 0x94,
+/*1D50*/0xE0, 0x54, 0xFB, 0xF0, 0x22, 0x12, 0x07, 0x2A,
+ 0x75, 0x83, 0x8E, 0xE4, 0x12, 0x07, 0x29, 0x74,
+/*1D60*/0x01, 0x12, 0x07, 0x29, 0xE4, 0x12, 0x08, 0xBE,
+ 0x75, 0x83, 0x8C, 0xE0, 0x44, 0x20, 0x12, 0x08,
+/*1D70*/0xBE, 0xE0, 0x54, 0xDF, 0xF0, 0x74, 0x84, 0x85,
+ 0x08, 0x82, 0xF5, 0x83, 0xE0, 0x54, 0x7F, 0xF0,
+/*1D80*/0xE0, 0x44, 0x80, 0xF0, 0x22, 0x75, 0x56, 0x01,
+ 0xE4, 0xFD, 0xF5, 0x57, 0xAF, 0x35, 0xFE, 0xFC,
+/*1D90*/0x12, 0x09, 0x15, 0x12, 0x1C, 0x9D, 0x12, 0x1E,
+ 0x7A, 0x12, 0x1C, 0x4C, 0xAF, 0x57, 0x7E, 0x00,
+/*1DA0*/0xAD, 0x56, 0x7C, 0x00, 0x12, 0x04, 0x44, 0xAF,
+ 0x56, 0x7E, 0x00, 0x02, 0x11, 0xEE, 0x75, 0x56,
+/*1DB0*/0x01, 0xE4, 0xFD, 0xF5, 0x57, 0xAF, 0x35, 0xFE,
+ 0xFC, 0x12, 0x09, 0x15, 0x12, 0x1C, 0x9D, 0x12,
+/*1DC0*/0x1E, 0x7A, 0x12, 0x1C, 0x4C, 0xAF, 0x57, 0x7E,
+ 0x00, 0xAD, 0x56, 0x7C, 0x00, 0x12, 0x04, 0x44,
+/*1DD0*/0xAF, 0x56, 0x7E, 0x00, 0x02, 0x11, 0xEE, 0xE4,
+ 0xF5, 0x16, 0x12, 0x0E, 0x44, 0xFE, 0xE5, 0x08,
+/*1DE0*/0x44, 0x05, 0xFF, 0x12, 0x0E, 0x65, 0x8F, 0x82,
+ 0x8E, 0x83, 0xF0, 0x05, 0x16, 0xE5, 0x16, 0xC3,
+/*1DF0*/0x94, 0x14, 0x40, 0xE6, 0xE5, 0x08, 0x12, 0x0E,
+ 0x2B, 0xE4, 0xF0, 0x22, 0xE4, 0xF5, 0x58, 0xF5,
+/*1E00*/0x59, 0xF5, 0x5A, 0xFF, 0xFE, 0xAD, 0x58, 0xFC,
+ 0x12, 0x09, 0x15, 0x7F, 0x04, 0x7E, 0x00, 0xAD,
+/*1E10*/0x58, 0x7C, 0x00, 0x12, 0x09, 0x15, 0x7F, 0x02,
+ 0x7E, 0x00, 0xAD, 0x58, 0x7C, 0x00, 0x02, 0x09,
+/*1E20*/0x15, 0xE5, 0x3C, 0x25, 0x3E, 0xFC, 0xE5, 0x42,
+ 0x24, 0x00, 0xFB, 0xE4, 0x33, 0xFA, 0xEC, 0xC3,
+/*1E30*/0x9B, 0xEA, 0x12, 0x07, 0x6B, 0x40, 0x0B, 0x8C,
+ 0x42, 0xE5, 0x3D, 0x25, 0x3F, 0xF5, 0x41, 0x8F,
+/*1E40*/0x40, 0x22, 0x12, 0x09, 0x0B, 0x22, 0x74, 0x84,
+ 0xF5, 0x18, 0x85, 0x08, 0x19, 0x85, 0x19, 0x82,
+/*1E50*/0x85, 0x18, 0x83, 0xE0, 0x54, 0x7F, 0xF0, 0xE0,
+ 0x44, 0x80, 0xF0, 0xE0, 0x44, 0x80, 0xF0, 0x22,
+/*1E60*/0xEF, 0x4E, 0x70, 0x0B, 0x12, 0x07, 0x2A, 0x75,
+ 0x83, 0xD2, 0xE0, 0x54, 0xDF, 0xF0, 0x22, 0x12,
+/*1E70*/0x07, 0x2A, 0x75, 0x83, 0xD2, 0xE0, 0x44, 0x20,
+ 0xF0, 0x22, 0x75, 0x58, 0x01, 0x90, 0x07, 0x26,
+/*1E80*/0x12, 0x07, 0x35, 0xE0, 0x54, 0x3F, 0xF5, 0x41,
+ 0x12, 0x07, 0x32, 0xE0, 0x54, 0x3F, 0xF5, 0x40,
+/*1E90*/0x22, 0x75, 0x56, 0x02, 0xE4, 0xF5, 0x57, 0x12,
+ 0x1D, 0xFC, 0xAF, 0x57, 0x7E, 0x00, 0xAD, 0x56,
+/*1EA0*/0x7C, 0x00, 0x02, 0x04, 0x44, 0xE4, 0xF5, 0x42,
+ 0xF5, 0x41, 0xF5, 0x40, 0xF5, 0x38, 0xF5, 0x39,
+/*1EB0*/0xF5, 0x3A, 0x22, 0xEF, 0x54, 0x07, 0xFF, 0xE5,
+ 0xF9, 0x54, 0xF8, 0x4F, 0xF5, 0xF9, 0x22, 0x7F,
+/*1EC0*/0x01, 0xE4, 0xFE, 0x0F, 0x0E, 0xBE, 0xFF, 0xFB,
+ 0x22, 0x01, 0x20, 0x00, 0x01, 0x04, 0x20, 0x00,
+/*1ED0*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/*1EE0*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/*1EF0*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/*1F00*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/*1F10*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/*1F20*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/*1F30*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/*1F40*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/*1F50*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/*1F60*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/*1F70*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/*1F80*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/*1F90*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/*1FA0*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/*1FB0*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/*1FC0*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/*1FD0*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/*1FE0*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/*1FF0*/0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x20, 0x11, 0x00, 0x04, 0x20, 0x00, 0x81
+};
diff --git a/gpxe/src/drivers/infiniband/qib_7220_regs.h b/gpxe/src/drivers/infiniband/qib_7220_regs.h
new file mode 100644
index 00000000..0dd3c53d
--- /dev/null
+++ b/gpxe/src/drivers/infiniband/qib_7220_regs.h
@@ -0,0 +1,1763 @@
+/*
+ * Copyright (c) 2008 QLogic Corporation. All rights reserved.
+ *
+ *
+ * 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 from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - 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.
+ *
+ * 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.
+ *
+ * This file is mechanically generated. Any hand-edits will be lost.
+ * If not now, soon.
+ */
+
+/* This file has been further processed by ./drivers/infiniband/qib_genbits.pl */
+
+
+#define QIB_7220_Revision_offset 0x00000000UL
+struct QIB_7220_Revision_pb {
+ pseudo_bit_t R_ChipRevMinor[8];
+ pseudo_bit_t R_ChipRevMajor[8];
+ pseudo_bit_t R_Arch[8];
+ pseudo_bit_t R_SW[8];
+ pseudo_bit_t BoardID[8];
+ pseudo_bit_t R_Palldium_Revcode[22];
+ pseudo_bit_t R_Palladium[1];
+ pseudo_bit_t R_Simulator[1];
+};
+struct QIB_7220_Revision {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_Revision_pb );
+};
+
+#define QIB_7220_Control_offset 0x00000008UL
+struct QIB_7220_Control_pb {
+ pseudo_bit_t SyncReset[1];
+ pseudo_bit_t FreezeMode[1];
+ pseudo_bit_t LinkEn[1];
+ pseudo_bit_t PCIERetryBufDiagEn[1];
+ pseudo_bit_t TxLatency[1];
+ pseudo_bit_t Reserved[1];
+ pseudo_bit_t PCIECplQDiagEn[1];
+ pseudo_bit_t SyncResetExceptPcieIRAMRST[1];
+ pseudo_bit_t _unused_0[56];
+};
+struct QIB_7220_Control {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_Control_pb );
+};
+
+#define QIB_7220_PageAlign_offset 0x00000010UL
+
+#define QIB_7220_PortCnt_offset 0x00000018UL
+
+#define QIB_7220_DbgPortSel_offset 0x00000020UL
+struct QIB_7220_DbgPortSel_pb {
+ pseudo_bit_t NibbleSel0[4];
+ pseudo_bit_t NibbleSel1[4];
+ pseudo_bit_t NibbleSel2[4];
+ pseudo_bit_t NibbleSel3[4];
+ pseudo_bit_t NibbleSel4[4];
+ pseudo_bit_t NibbleSel5[4];
+ pseudo_bit_t NibbleSel6[4];
+ pseudo_bit_t NibbleSel7[4];
+ pseudo_bit_t SrcMuxSel[14];
+ pseudo_bit_t DbgClkPortSel[5];
+ pseudo_bit_t EnDbgPort[1];
+ pseudo_bit_t EnEnhancedDebugMode[1];
+ pseudo_bit_t EnhMode_SrcMuxSelIndex[10];
+ pseudo_bit_t EnhMode_SrcMuxSelWrEn[1];
+};
+struct QIB_7220_DbgPortSel {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_DbgPortSel_pb );
+};
+
+#define QIB_7220_DebugSigsIntSel_offset 0x00000028UL
+struct QIB_7220_DebugSigsIntSel_pb {
+ pseudo_bit_t debug_port_sel_pcs_pipe_lane07[3];
+ pseudo_bit_t debug_port_sel_pcs_pipe_lane815[3];
+ pseudo_bit_t debug_port_sel_pcs_sdout[1];
+ pseudo_bit_t debug_port_sel_pcs_symlock_elfifo_lane[4];
+ pseudo_bit_t debug_port_sel_pcs_rxdet_encdec_lane[4];
+ pseudo_bit_t debug_port_sel_pcie_rx_tx[1];
+ pseudo_bit_t debug_port_sel_xgxs[4];
+ pseudo_bit_t debug_port_sel_epb_pcie[1];
+ pseudo_bit_t _unused_0[43];
+};
+struct QIB_7220_DebugSigsIntSel {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_DebugSigsIntSel_pb );
+};
+
+#define QIB_7220_SendRegBase_offset 0x00000030UL
+
+#define QIB_7220_UserRegBase_offset 0x00000038UL
+
+#define QIB_7220_CntrRegBase_offset 0x00000040UL
+
+#define QIB_7220_Scratch_offset 0x00000048UL
+
+#define QIB_7220_REG_000050_offset 0x00000050UL
+
+#define QIB_7220_IntBlocked_offset 0x00000060UL
+struct QIB_7220_IntBlocked_pb {
+ pseudo_bit_t RcvAvail0IntBlocked[1];
+ pseudo_bit_t RcvAvail1IntBlocked[1];
+ pseudo_bit_t RcvAvail2IntBlocked[1];
+ pseudo_bit_t RcvAvail3IntBlocked[1];
+ pseudo_bit_t RcvAvail4IntBlocked[1];
+ pseudo_bit_t RcvAvail5IntBlocked[1];
+ pseudo_bit_t RcvAvail6IntBlocked[1];
+ pseudo_bit_t RcvAvail7IntBlocked[1];
+ pseudo_bit_t RcvAvail8IntBlocked[1];
+ pseudo_bit_t RcvAvail9IntBlocked[1];
+ pseudo_bit_t RcvAvail10IntBlocked[1];
+ pseudo_bit_t RcvAvail11IntBlocked[1];
+ pseudo_bit_t RcvAvail12IntBlocked[1];
+ pseudo_bit_t RcvAvail13IntBlocked[1];
+ pseudo_bit_t RcvAvail14IntBlocked[1];
+ pseudo_bit_t RcvAvail15IntBlocked[1];
+ pseudo_bit_t RcvAvail16IntBlocked[1];
+ pseudo_bit_t Reserved1[9];
+ pseudo_bit_t JIntBlocked[1];
+ pseudo_bit_t IBSerdesTrimDoneIntBlocked[1];
+ pseudo_bit_t assertGPIOIntBlocked[1];
+ pseudo_bit_t PioBufAvailIntBlocked[1];
+ pseudo_bit_t PioSetIntBlocked[1];
+ pseudo_bit_t ErrorIntBlocked[1];
+ pseudo_bit_t RcvUrg0IntBlocked[1];
+ pseudo_bit_t RcvUrg1IntBlocked[1];
+ pseudo_bit_t RcvUrg2IntBlocked[1];
+ pseudo_bit_t RcvUrg3IntBlocked[1];
+ pseudo_bit_t RcvUrg4IntBlocked[1];
+ pseudo_bit_t RcvUrg5IntBlocked[1];
+ pseudo_bit_t RcvUrg6IntBlocked[1];
+ pseudo_bit_t RcvUrg7IntBlocked[1];
+ pseudo_bit_t RcvUrg8IntBlocked[1];
+ pseudo_bit_t RcvUrg9IntBlocked[1];
+ pseudo_bit_t RcvUrg10IntBlocked[1];
+ pseudo_bit_t RcvUrg11IntBlocked[1];
+ pseudo_bit_t RcvUrg12IntBlocked[1];
+ pseudo_bit_t RcvUrg13IntBlocked[1];
+ pseudo_bit_t RcvUrg14IntBlocked[1];
+ pseudo_bit_t RcvUrg15IntBlocked[1];
+ pseudo_bit_t RcvUrg16IntBlocked[1];
+ pseudo_bit_t Reserved[13];
+ pseudo_bit_t SDmaDisabledBlocked[1];
+ pseudo_bit_t SDmaIntBlocked[1];
+};
+struct QIB_7220_IntBlocked {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_IntBlocked_pb );
+};
+
+#define QIB_7220_IntMask_offset 0x00000068UL
+struct QIB_7220_IntMask_pb {
+ pseudo_bit_t RcvAvail0IntMask[1];
+ pseudo_bit_t RcvAvail1IntMask[1];
+ pseudo_bit_t RcvAvail2IntMask[1];
+ pseudo_bit_t RcvAvail3IntMask[1];
+ pseudo_bit_t RcvAvail4IntMask[1];
+ pseudo_bit_t RcvAvail5IntMask[1];
+ pseudo_bit_t RcvAvail6IntMask[1];
+ pseudo_bit_t RcvAvail7IntMask[1];
+ pseudo_bit_t RcvAvail8IntMask[1];
+ pseudo_bit_t RcvAvail9IntMask[1];
+ pseudo_bit_t RcvAvail10IntMask[1];
+ pseudo_bit_t RcvAvail11IntMask[1];
+ pseudo_bit_t RcvAvail12IntMask[1];
+ pseudo_bit_t RcvAvail13IntMask[1];
+ pseudo_bit_t RcvAvail14IntMask[1];
+ pseudo_bit_t RcvAvail15IntMask[1];
+ pseudo_bit_t RcvAvail16IntMask[1];
+ pseudo_bit_t Reserved1[9];
+ pseudo_bit_t JIntMask[1];
+ pseudo_bit_t IBSerdesTrimDoneIntMask[1];
+ pseudo_bit_t assertGPIOIntMask[1];
+ pseudo_bit_t PioBufAvailIntMask[1];
+ pseudo_bit_t PioSetIntMask[1];
+ pseudo_bit_t ErrorIntMask[1];
+ pseudo_bit_t RcvUrg0IntMask[1];
+ pseudo_bit_t RcvUrg1IntMask[1];
+ pseudo_bit_t RcvUrg2IntMask[1];
+ pseudo_bit_t RcvUrg3IntMask[1];
+ pseudo_bit_t RcvUrg4IntMask[1];
+ pseudo_bit_t RcvUrg5IntMask[1];
+ pseudo_bit_t RcvUrg6IntMask[1];
+ pseudo_bit_t RcvUrg7IntMask[1];
+ pseudo_bit_t RcvUrg8IntMask[1];
+ pseudo_bit_t RcvUrg9IntMask[1];
+ pseudo_bit_t RcvUrg10IntMask[1];
+ pseudo_bit_t RcvUrg11IntMask[1];
+ pseudo_bit_t RcvUrg12IntMask[1];
+ pseudo_bit_t RcvUrg13IntMask[1];
+ pseudo_bit_t RcvUrg14IntMask[1];
+ pseudo_bit_t RcvUrg15IntMask[1];
+ pseudo_bit_t RcvUrg16IntMask[1];
+ pseudo_bit_t Reserved[13];
+ pseudo_bit_t SDmaDisabledMasked[1];
+ pseudo_bit_t SDmaIntMask[1];
+};
+struct QIB_7220_IntMask {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_IntMask_pb );
+};
+
+#define QIB_7220_IntStatus_offset 0x00000070UL
+struct QIB_7220_IntStatus_pb {
+ pseudo_bit_t RcvAvail0[1];
+ pseudo_bit_t RcvAvail1[1];
+ pseudo_bit_t RcvAvail2[1];
+ pseudo_bit_t RcvAvail3[1];
+ pseudo_bit_t RcvAvail4[1];
+ pseudo_bit_t RcvAvail5[1];
+ pseudo_bit_t RcvAvail6[1];
+ pseudo_bit_t RcvAvail7[1];
+ pseudo_bit_t RcvAvail8[1];
+ pseudo_bit_t RcvAvail9[1];
+ pseudo_bit_t RcvAvail10[1];
+ pseudo_bit_t RcvAvail11[1];
+ pseudo_bit_t RcvAvail12[1];
+ pseudo_bit_t RcvAvail13[1];
+ pseudo_bit_t RcvAvail14[1];
+ pseudo_bit_t RcvAvail15[1];
+ pseudo_bit_t RcvAvail16[1];
+ pseudo_bit_t Reserved1[9];
+ pseudo_bit_t JInt[1];
+ pseudo_bit_t IBSerdesTrimDone[1];
+ pseudo_bit_t assertGPIO[1];
+ pseudo_bit_t PioBufAvail[1];
+ pseudo_bit_t PioSent[1];
+ pseudo_bit_t Error[1];
+ pseudo_bit_t RcvUrg0[1];
+ pseudo_bit_t RcvUrg1[1];
+ pseudo_bit_t RcvUrg2[1];
+ pseudo_bit_t RcvUrg3[1];
+ pseudo_bit_t RcvUrg4[1];
+ pseudo_bit_t RcvUrg5[1];
+ pseudo_bit_t RcvUrg6[1];
+ pseudo_bit_t RcvUrg7[1];
+ pseudo_bit_t RcvUrg8[1];
+ pseudo_bit_t RcvUrg9[1];
+ pseudo_bit_t RcvUrg10[1];
+ pseudo_bit_t RcvUrg11[1];
+ pseudo_bit_t RcvUrg12[1];
+ pseudo_bit_t RcvUrg13[1];
+ pseudo_bit_t RcvUrg14[1];
+ pseudo_bit_t RcvUrg15[1];
+ pseudo_bit_t RcvUrg16[1];
+ pseudo_bit_t Reserved[13];
+ pseudo_bit_t SDmaDisabled[1];
+ pseudo_bit_t SDmaInt[1];
+};
+struct QIB_7220_IntStatus {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_IntStatus_pb );
+};
+
+#define QIB_7220_IntClear_offset 0x00000078UL
+struct QIB_7220_IntClear_pb {
+ pseudo_bit_t RcvAvail0IntClear[1];
+ pseudo_bit_t RcvAvail1IntClear[1];
+ pseudo_bit_t RcvAvail2IntClear[1];
+ pseudo_bit_t RcvAvail3IntClear[1];
+ pseudo_bit_t RcvAvail4IntClear[1];
+ pseudo_bit_t RcvAvail5IntClear[1];
+ pseudo_bit_t RcvAvail6IntClear[1];
+ pseudo_bit_t RcvAvail7IntClear[1];
+ pseudo_bit_t RcvAvail8IntClear[1];
+ pseudo_bit_t RcvAvail9IntClear[1];
+ pseudo_bit_t RcvAvail10IntClear[1];
+ pseudo_bit_t RcvAvail11IntClear[1];
+ pseudo_bit_t RcvAvail12IntClear[1];
+ pseudo_bit_t RcvAvail13IntClear[1];
+ pseudo_bit_t RcvAvail14IntClear[1];
+ pseudo_bit_t RcvAvail15IntClear[1];
+ pseudo_bit_t RcvAvail16IntClear[1];
+ pseudo_bit_t Reserved1[9];
+ pseudo_bit_t JIntClear[1];
+ pseudo_bit_t IBSerdesTrimDoneClear[1];
+ pseudo_bit_t assertGPIOIntClear[1];
+ pseudo_bit_t PioBufAvailIntClear[1];
+ pseudo_bit_t PioSetIntClear[1];
+ pseudo_bit_t ErrorIntClear[1];
+ pseudo_bit_t RcvUrg0IntClear[1];
+ pseudo_bit_t RcvUrg1IntClear[1];
+ pseudo_bit_t RcvUrg2IntClear[1];
+ pseudo_bit_t RcvUrg3IntClear[1];
+ pseudo_bit_t RcvUrg4IntClear[1];
+ pseudo_bit_t RcvUrg5IntClear[1];
+ pseudo_bit_t RcvUrg6IntClear[1];
+ pseudo_bit_t RcvUrg7IntClear[1];
+ pseudo_bit_t RcvUrg8IntClear[1];
+ pseudo_bit_t RcvUrg9IntClear[1];
+ pseudo_bit_t RcvUrg10IntClear[1];
+ pseudo_bit_t RcvUrg11IntClear[1];
+ pseudo_bit_t RcvUrg12IntClear[1];
+ pseudo_bit_t RcvUrg13IntClear[1];
+ pseudo_bit_t RcvUrg14IntClear[1];
+ pseudo_bit_t RcvUrg15IntClear[1];
+ pseudo_bit_t RcvUrg16IntClear[1];
+ pseudo_bit_t Reserved[13];
+ pseudo_bit_t SDmaDisabledClear[1];
+ pseudo_bit_t SDmaIntClear[1];
+};
+struct QIB_7220_IntClear {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_IntClear_pb );
+};
+
+#define QIB_7220_ErrMask_offset 0x00000080UL
+struct QIB_7220_ErrMask_pb {
+ pseudo_bit_t RcvFormatErrMask[1];
+ pseudo_bit_t RcvVCRCErrMask[1];
+ pseudo_bit_t RcvICRCErrMask[1];
+ pseudo_bit_t RcvMinPktLenErrMask[1];
+ pseudo_bit_t RcvMaxPktLenErrMask[1];
+ pseudo_bit_t RcvLongPktLenErrMask[1];
+ pseudo_bit_t RcvShortPktLenErrMask[1];
+ pseudo_bit_t RcvUnexpectedCharErrMask[1];
+ pseudo_bit_t RcvUnsupportedVLErrMask[1];
+ pseudo_bit_t RcvEBPErrMask[1];
+ pseudo_bit_t RcvIBFlowErrMask[1];
+ pseudo_bit_t RcvBadVersionErrMask[1];
+ pseudo_bit_t RcvEgrFullErrMask[1];
+ pseudo_bit_t RcvHdrFullErrMask[1];
+ pseudo_bit_t RcvBadTidErrMask[1];
+ pseudo_bit_t RcvHdrLenErrMask[1];
+ pseudo_bit_t RcvHdrErrMask[1];
+ pseudo_bit_t RcvIBLostLinkErrMask[1];
+ pseudo_bit_t Reserved1[9];
+ pseudo_bit_t SendSpecialTriggerErrMask[1];
+ pseudo_bit_t SDmaDisabledErrMask[1];
+ pseudo_bit_t SendMinPktLenErrMask[1];
+ pseudo_bit_t SendMaxPktLenErrMask[1];
+ pseudo_bit_t SendUnderRunErrMask[1];
+ pseudo_bit_t SendPktLenErrMask[1];
+ pseudo_bit_t SendDroppedSmpPktErrMask[1];
+ pseudo_bit_t SendDroppedDataPktErrMask[1];
+ pseudo_bit_t SendPioArmLaunchErrMask[1];
+ pseudo_bit_t SendUnexpectedPktNumErrMask[1];
+ pseudo_bit_t SendUnsupportedVLErrMask[1];
+ pseudo_bit_t SendBufMisuseErrMask[1];
+ pseudo_bit_t SDmaGenMismatchErrMask[1];
+ pseudo_bit_t SDmaOutOfBoundErrMask[1];
+ pseudo_bit_t SDmaTailOutOfBoundErrMask[1];
+ pseudo_bit_t SDmaBaseErrMask[1];
+ pseudo_bit_t SDma1stDescErrMask[1];
+ pseudo_bit_t SDmaRpyTagErrMask[1];
+ pseudo_bit_t SDmaDwEnErrMask[1];
+ pseudo_bit_t SDmaMissingDwErrMask[1];
+ pseudo_bit_t SDmaUnexpDataErrMask[1];
+ pseudo_bit_t IBStatusChangedMask[1];
+ pseudo_bit_t InvalidAddrErrMask[1];
+ pseudo_bit_t ResetNegatedMask[1];
+ pseudo_bit_t HardwareErrMask[1];
+ pseudo_bit_t SDmaDescAddrMisalignErrMask[1];
+ pseudo_bit_t InvalidEEPCmdMask[1];
+ pseudo_bit_t Reserved[10];
+};
+struct QIB_7220_ErrMask {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_ErrMask_pb );
+};
+
+#define QIB_7220_ErrStatus_offset 0x00000088UL
+struct QIB_7220_ErrStatus_pb {
+ pseudo_bit_t RcvFormatErr[1];
+ pseudo_bit_t RcvVCRCErr[1];
+ pseudo_bit_t RcvICRCErr[1];
+ pseudo_bit_t RcvMinPktLenErr[1];
+ pseudo_bit_t RcvMaxPktLenErr[1];
+ pseudo_bit_t RcvLongPktLenErr[1];
+ pseudo_bit_t RcvShortPktLenErr[1];
+ pseudo_bit_t RcvUnexpectedCharErr[1];
+ pseudo_bit_t RcvUnsupportedVLErr[1];
+ pseudo_bit_t RcvEBPErr[1];
+ pseudo_bit_t RcvIBFlowErr[1];
+ pseudo_bit_t RcvBadVersionErr[1];
+ pseudo_bit_t RcvEgrFullErr[1];
+ pseudo_bit_t RcvHdrFullErr[1];
+ pseudo_bit_t RcvBadTidErr[1];
+ pseudo_bit_t RcvHdrLenErr[1];
+ pseudo_bit_t RcvHdrErr[1];
+ pseudo_bit_t RcvIBLostLinkErr[1];
+ pseudo_bit_t Reserved1[9];
+ pseudo_bit_t SendSpecialTriggerErr[1];
+ pseudo_bit_t SDmaDisabledErr[1];
+ pseudo_bit_t SendMinPktLenErr[1];
+ pseudo_bit_t SendMaxPktLenErr[1];
+ pseudo_bit_t SendUnderRunErr[1];
+ pseudo_bit_t SendPktLenErr[1];
+ pseudo_bit_t SendDroppedSmpPktErr[1];
+ pseudo_bit_t SendDroppedDataPktErr[1];
+ pseudo_bit_t SendPioArmLaunchErr[1];
+ pseudo_bit_t SendUnexpectedPktNumErr[1];
+ pseudo_bit_t SendUnsupportedVLErr[1];
+ pseudo_bit_t SendBufMisuseErr[1];
+ pseudo_bit_t SDmaGenMismatchErr[1];
+ pseudo_bit_t SDmaOutOfBoundErr[1];
+ pseudo_bit_t SDmaTailOutOfBoundErr[1];
+ pseudo_bit_t SDmaBaseErr[1];
+ pseudo_bit_t SDma1stDescErr[1];
+ pseudo_bit_t SDmaRpyTagErr[1];
+ pseudo_bit_t SDmaDwEnErr[1];
+ pseudo_bit_t SDmaMissingDwErr[1];
+ pseudo_bit_t SDmaUnexpDataErr[1];
+ pseudo_bit_t IBStatusChanged[1];
+ pseudo_bit_t InvalidAddrErr[1];
+ pseudo_bit_t ResetNegated[1];
+ pseudo_bit_t HardwareErr[1];
+ pseudo_bit_t SDmaDescAddrMisalignErr[1];
+ pseudo_bit_t InvalidEEPCmdErr[1];
+ pseudo_bit_t Reserved[10];
+};
+struct QIB_7220_ErrStatus {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_ErrStatus_pb );
+};
+
+#define QIB_7220_ErrClear_offset 0x00000090UL
+struct QIB_7220_ErrClear_pb {
+ pseudo_bit_t RcvFormatErrClear[1];
+ pseudo_bit_t RcvVCRCErrClear[1];
+ pseudo_bit_t RcvICRCErrClear[1];
+ pseudo_bit_t RcvMinPktLenErrClear[1];
+ pseudo_bit_t RcvMaxPktLenErrClear[1];
+ pseudo_bit_t RcvLongPktLenErrClear[1];
+ pseudo_bit_t RcvShortPktLenErrClear[1];
+ pseudo_bit_t RcvUnexpectedCharErrClear[1];
+ pseudo_bit_t RcvUnsupportedVLErrClear[1];
+ pseudo_bit_t RcvEBPErrClear[1];
+ pseudo_bit_t RcvIBFlowErrClear[1];
+ pseudo_bit_t RcvBadVersionErrClear[1];
+ pseudo_bit_t RcvEgrFullErrClear[1];
+ pseudo_bit_t RcvHdrFullErrClear[1];
+ pseudo_bit_t RcvBadTidErrClear[1];
+ pseudo_bit_t RcvHdrLenErrClear[1];
+ pseudo_bit_t RcvHdrErrClear[1];
+ pseudo_bit_t RcvIBLostLinkErrClear[1];
+ pseudo_bit_t Reserved1[9];
+ pseudo_bit_t SendSpecialTriggerErrClear[1];
+ pseudo_bit_t SDmaDisabledErrClear[1];
+ pseudo_bit_t SendMinPktLenErrClear[1];
+ pseudo_bit_t SendMaxPktLenErrClear[1];
+ pseudo_bit_t SendUnderRunErrClear[1];
+ pseudo_bit_t SendPktLenErrClear[1];
+ pseudo_bit_t SendDroppedSmpPktErrClear[1];
+ pseudo_bit_t SendDroppedDataPktErrClear[1];
+ pseudo_bit_t SendPioArmLaunchErrClear[1];
+ pseudo_bit_t SendUnexpectedPktNumErrClear[1];
+ pseudo_bit_t SendUnsupportedVLErrClear[1];
+ pseudo_bit_t SendBufMisuseErrClear[1];
+ pseudo_bit_t SDmaGenMismatchErrClear[1];
+ pseudo_bit_t SDmaOutOfBoundErrClear[1];
+ pseudo_bit_t SDmaTailOutOfBoundErrClear[1];
+ pseudo_bit_t SDmaBaseErrClear[1];
+ pseudo_bit_t SDma1stDescErrClear[1];
+ pseudo_bit_t SDmaRpyTagErrClear[1];
+ pseudo_bit_t SDmaDwEnErrClear[1];
+ pseudo_bit_t SDmaMissingDwErrClear[1];
+ pseudo_bit_t SDmaUnexpDataErrClear[1];
+ pseudo_bit_t IBStatusChangedClear[1];
+ pseudo_bit_t InvalidAddrErrClear[1];
+ pseudo_bit_t ResetNegatedClear[1];
+ pseudo_bit_t HardwareErrClear[1];
+ pseudo_bit_t SDmaDescAddrMisalignErrClear[1];
+ pseudo_bit_t InvalidEEPCmdErrClear[1];
+ pseudo_bit_t Reserved[10];
+};
+struct QIB_7220_ErrClear {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_ErrClear_pb );
+};
+
+#define QIB_7220_HwErrMask_offset 0x00000098UL
+struct QIB_7220_HwErrMask_pb {
+ pseudo_bit_t PCIeMemParityErrMask[8];
+ pseudo_bit_t Reserved3[20];
+ pseudo_bit_t SDmaMemReadErrMask[1];
+ pseudo_bit_t PoisonedTLPMask[1];
+ pseudo_bit_t PcieCplTimeoutMask[1];
+ pseudo_bit_t PCIeBusParityErrMask[3];
+ pseudo_bit_t Reserved2[2];
+ pseudo_bit_t PCIEOct0_uC_MemoryParityErrMask[1];
+ pseudo_bit_t PCIEOct1_uC_MemoryParityErrMask[1];
+ pseudo_bit_t IB_uC_MemoryParityErrMask[1];
+ pseudo_bit_t DDSRXEQMemoryParityErrMask[1];
+ pseudo_bit_t TXEMemParityErrMask[4];
+ pseudo_bit_t RXEMemParityErrMask[7];
+ pseudo_bit_t Reserved1[3];
+ pseudo_bit_t PowerOnBISTFailedMask[1];
+ pseudo_bit_t Reserved[1];
+ pseudo_bit_t PCIESerdesQ0PClkNotDetectMask[1];
+ pseudo_bit_t PCIESerdesQ1PClkNotDetectMask[1];
+ pseudo_bit_t PCIESerdesQ2PClkNotDetectMask[1];
+ pseudo_bit_t PCIESerdesQ3PClkNotDetectMask[1];
+ pseudo_bit_t IBSerdesPClkNotDetectMask[1];
+ pseudo_bit_t Clk_uC_PLLNotLockedMask[1];
+ pseudo_bit_t IBCBusToSPCParityErrMask[1];
+ pseudo_bit_t IBCBusFromSPCParityErrMask[1];
+};
+struct QIB_7220_HwErrMask {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_HwErrMask_pb );
+};
+
+#define QIB_7220_HwErrStatus_offset 0x000000a0UL
+struct QIB_7220_HwErrStatus_pb {
+ pseudo_bit_t PCIeMemParity[8];
+ pseudo_bit_t Reserved3[20];
+ pseudo_bit_t SDmaMemReadErr[1];
+ pseudo_bit_t PoisenedTLP[1];
+ pseudo_bit_t PcieCplTimeout[1];
+ pseudo_bit_t PCIeBusParity[3];
+ pseudo_bit_t Reserved2[2];
+ pseudo_bit_t PCIE_uC_Oct0MemoryParityErr[1];
+ pseudo_bit_t PCIE_uC_Oct1MemoryParityErr[1];
+ pseudo_bit_t IB_uC_MemoryParityErr[1];
+ pseudo_bit_t DDSRXEQMemoryParityErr[1];
+ pseudo_bit_t TXEMemParity[4];
+ pseudo_bit_t RXEMemParity[7];
+ pseudo_bit_t Reserved1[3];
+ pseudo_bit_t PowerOnBISTFailed[1];
+ pseudo_bit_t Reserved[1];
+ pseudo_bit_t PCIESerdesQ0PClkNotDetect[1];
+ pseudo_bit_t PCIESerdesQ1PClkNotDetect[1];
+ pseudo_bit_t PCIESerdesQ2PClkNotDetect[1];
+ pseudo_bit_t PCIESerdesQ3PClkNotDetect[1];
+ pseudo_bit_t IBSerdesPClkNotDetect[1];
+ pseudo_bit_t Clk_uC_PLLNotLocked[1];
+ pseudo_bit_t IBCBusToSPCParityErr[1];
+ pseudo_bit_t IBCBusFromSPCParityErr[1];
+};
+struct QIB_7220_HwErrStatus {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_HwErrStatus_pb );
+};
+
+#define QIB_7220_HwErrClear_offset 0x000000a8UL
+struct QIB_7220_HwErrClear_pb {
+ pseudo_bit_t PCIeMemParityClr[8];
+ pseudo_bit_t Reserved3[20];
+ pseudo_bit_t SDmaMemReadErrClear[1];
+ pseudo_bit_t PoisonedTLPClear[1];
+ pseudo_bit_t PcieCplTimeoutClear[1];
+ pseudo_bit_t PCIeBusParityClr[3];
+ pseudo_bit_t Reserved2[2];
+ pseudo_bit_t PCIE_uC_Oct0MemoryParityErrClear[1];
+ pseudo_bit_t PCIE_uC_Oct1MemoryParityErrClear[1];
+ pseudo_bit_t IB_uC_MemoryParityErrClear[1];
+ pseudo_bit_t DDSRXEQMemoryParityErrClear[1];
+ pseudo_bit_t TXEMemParityClear[4];
+ pseudo_bit_t RXEMemParityClear[7];
+ pseudo_bit_t Reserved1[3];
+ pseudo_bit_t PowerOnBISTFailedClear[1];
+ pseudo_bit_t Reserved[1];
+ pseudo_bit_t PCIESerdesQ0PClkNotDetectClear[1];
+ pseudo_bit_t PCIESerdesQ1PClkNotDetectClear[1];
+ pseudo_bit_t PCIESerdesQ2PClkNotDetectClear[1];
+ pseudo_bit_t PCIESerdesQ3PClkNotDetectClear[1];
+ pseudo_bit_t IBSerdesPClkNotDetectClear[1];
+ pseudo_bit_t Clk_uC_PLLNotLockedClear[1];
+ pseudo_bit_t IBCBusToSPCparityErrClear[1];
+ pseudo_bit_t IBCBusFromSPCParityErrClear[1];
+};
+struct QIB_7220_HwErrClear {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_HwErrClear_pb );
+};
+
+#define QIB_7220_HwDiagCtrl_offset 0x000000b0UL
+struct QIB_7220_HwDiagCtrl_pb {
+ pseudo_bit_t forcePCIeMemParity[8];
+ pseudo_bit_t Reserved2[23];
+ pseudo_bit_t forcePCIeBusParity[4];
+ pseudo_bit_t Reserved1[1];
+ pseudo_bit_t ForcePCIE_uC_Oct0MemoryParityErr[1];
+ pseudo_bit_t ForcePCIE_uC_Oct1MemoryParityErr[1];
+ pseudo_bit_t ForceIB_uC_MemoryParityErr[1];
+ pseudo_bit_t ForceDDSRXEQMemoryParityErr[1];
+ pseudo_bit_t ForceTxMemparityErr[4];
+ pseudo_bit_t ForceRxMemParityErr[7];
+ pseudo_bit_t Reserved[9];
+ pseudo_bit_t CounterDisable[1];
+ pseudo_bit_t CounterWrEnable[1];
+ pseudo_bit_t ForceIBCBusToSPCParityErr[1];
+ pseudo_bit_t ForceIBCBusFromSPCParityErr[1];
+};
+struct QIB_7220_HwDiagCtrl {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_HwDiagCtrl_pb );
+};
+
+#define QIB_7220_REG_0000B8_offset 0x000000b8UL
+
+#define QIB_7220_IBCStatus_offset 0x000000c0UL
+struct QIB_7220_IBCStatus_pb {
+ pseudo_bit_t LinkTrainingState[5];
+ pseudo_bit_t LinkState[3];
+ pseudo_bit_t LinkSpeedActive[1];
+ pseudo_bit_t LinkWidthActive[1];
+ pseudo_bit_t DDS_RXEQ_FAIL[1];
+ pseudo_bit_t IB_SERDES_TRIM_DONE[1];
+ pseudo_bit_t IBRxLaneReversed[1];
+ pseudo_bit_t IBTxLaneReversed[1];
+ pseudo_bit_t Reserved[16];
+ pseudo_bit_t TxReady[1];
+ pseudo_bit_t TxCreditOk[1];
+ pseudo_bit_t _unused_0[32];
+};
+struct QIB_7220_IBCStatus {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_IBCStatus_pb );
+};
+
+#define QIB_7220_IBCCtrl_offset 0x000000c8UL
+struct QIB_7220_IBCCtrl_pb {
+ pseudo_bit_t FlowCtrlPeriod[8];
+ pseudo_bit_t FlowCtrlWaterMark[8];
+ pseudo_bit_t LinkInitCmd[3];
+ pseudo_bit_t LinkCmd[2];
+ pseudo_bit_t MaxPktLen[11];
+ pseudo_bit_t PhyerrThreshold[4];
+ pseudo_bit_t OverrunThreshold[4];
+ pseudo_bit_t CreditScale[3];
+ pseudo_bit_t Reserved[19];
+ pseudo_bit_t LinkDownDefaultState[1];
+ pseudo_bit_t Loopback[1];
+};
+struct QIB_7220_IBCCtrl {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_IBCCtrl_pb );
+};
+
+#define QIB_7220_EXTStatus_offset 0x000000d0UL
+struct QIB_7220_EXTStatus_pb {
+ pseudo_bit_t Reserved2[14];
+ pseudo_bit_t MemBISTEndTest[1];
+ pseudo_bit_t MemBISTDisabled[1];
+ pseudo_bit_t Reserved1[16];
+ pseudo_bit_t Reserved[16];
+ pseudo_bit_t GPIOIn[16];
+};
+struct QIB_7220_EXTStatus {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_EXTStatus_pb );
+};
+
+#define QIB_7220_EXTCtrl_offset 0x000000d8UL
+struct QIB_7220_EXTCtrl_pb {
+ pseudo_bit_t LEDGblErrRedOff[1];
+ pseudo_bit_t LEDGblOkGreenOn[1];
+ pseudo_bit_t LEDPriPortYellowOn[1];
+ pseudo_bit_t LEDPriPortGreenOn[1];
+ pseudo_bit_t Reserved[28];
+ pseudo_bit_t GPIOInvert[16];
+ pseudo_bit_t GPIOOe[16];
+};
+struct QIB_7220_EXTCtrl {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_EXTCtrl_pb );
+};
+
+#define QIB_7220_GPIOOut_offset 0x000000e0UL
+
+#define QIB_7220_GPIOMask_offset 0x000000e8UL
+
+#define QIB_7220_GPIOStatus_offset 0x000000f0UL
+
+#define QIB_7220_GPIOClear_offset 0x000000f8UL
+
+#define QIB_7220_RcvCtrl_offset 0x00000100UL
+struct QIB_7220_RcvCtrl_pb {
+ pseudo_bit_t PortEnable[17];
+ pseudo_bit_t IntrAvail[17];
+ pseudo_bit_t RcvPartitionKeyDisable[1];
+ pseudo_bit_t TailUpd[1];
+ pseudo_bit_t PortCfg[2];
+ pseudo_bit_t RcvQPMapEnable[1];
+ pseudo_bit_t Reserved[25];
+};
+struct QIB_7220_RcvCtrl {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvCtrl_pb );
+};
+
+#define QIB_7220_RcvBTHQP_offset 0x00000108UL
+struct QIB_7220_RcvBTHQP_pb {
+ pseudo_bit_t RcvBTHQP[24];
+ pseudo_bit_t Reserved[8];
+ pseudo_bit_t _unused_0[32];
+};
+struct QIB_7220_RcvBTHQP {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvBTHQP_pb );
+};
+
+#define QIB_7220_RcvHdrSize_offset 0x00000110UL
+
+#define QIB_7220_RcvHdrCnt_offset 0x00000118UL
+
+#define QIB_7220_RcvHdrEntSize_offset 0x00000120UL
+
+#define QIB_7220_RcvTIDBase_offset 0x00000128UL
+
+#define QIB_7220_RcvTIDCnt_offset 0x00000130UL
+
+#define QIB_7220_RcvEgrBase_offset 0x00000138UL
+
+#define QIB_7220_RcvEgrCnt_offset 0x00000140UL
+
+#define QIB_7220_RcvBufBase_offset 0x00000148UL
+
+#define QIB_7220_RcvBufSize_offset 0x00000150UL
+
+#define QIB_7220_RxIntMemBase_offset 0x00000158UL
+
+#define QIB_7220_RxIntMemSize_offset 0x00000160UL
+
+#define QIB_7220_RcvPartitionKey_offset 0x00000168UL
+
+#define QIB_7220_RcvQPMulticastPort_offset 0x00000170UL
+struct QIB_7220_RcvQPMulticastPort_pb {
+ pseudo_bit_t RcvQpMcPort[5];
+ pseudo_bit_t Reserved[59];
+};
+struct QIB_7220_RcvQPMulticastPort {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvQPMulticastPort_pb );
+};
+
+#define QIB_7220_RcvPktLEDCnt_offset 0x00000178UL
+struct QIB_7220_RcvPktLEDCnt_pb {
+ pseudo_bit_t OFFperiod[32];
+ pseudo_bit_t ONperiod[32];
+};
+struct QIB_7220_RcvPktLEDCnt {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvPktLEDCnt_pb );
+};
+
+#define QIB_7220_IBCDDRCtrl_offset 0x00000180UL
+struct QIB_7220_IBCDDRCtrl_pb {
+ pseudo_bit_t IB_ENHANCED_MODE[1];
+ pseudo_bit_t SD_SPEED[1];
+ pseudo_bit_t SD_SPEED_SDR[1];
+ pseudo_bit_t SD_SPEED_DDR[1];
+ pseudo_bit_t SD_SPEED_QDR[1];
+ pseudo_bit_t IB_NUM_CHANNELS[2];
+ pseudo_bit_t IB_POLARITY_REV_SUPP[1];
+ pseudo_bit_t IB_LANE_REV_SUPPORTED[1];
+ pseudo_bit_t SD_RX_EQUAL_ENABLE[1];
+ pseudo_bit_t SD_ADD_ENB[1];
+ pseudo_bit_t SD_DDSV[1];
+ pseudo_bit_t SD_DDS[4];
+ pseudo_bit_t HRTBT_ENB[1];
+ pseudo_bit_t HRTBT_AUTO[1];
+ pseudo_bit_t HRTBT_PORT[8];
+ pseudo_bit_t HRTBT_REQ[1];
+ pseudo_bit_t Reserved[5];
+ pseudo_bit_t IB_DLID[16];
+ pseudo_bit_t IB_DLID_MASK[16];
+};
+struct QIB_7220_IBCDDRCtrl {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_IBCDDRCtrl_pb );
+};
+
+#define QIB_7220_HRTBT_GUID_offset 0x00000188UL
+
+#define QIB_7220_IB_SDTEST_IF_TX_offset 0x00000190UL
+struct QIB_7220_IB_SDTEST_IF_TX_pb {
+ pseudo_bit_t TS_T_TX_VALID[1];
+ pseudo_bit_t TS_3_TX_VALID[1];
+ pseudo_bit_t Reserved1[9];
+ pseudo_bit_t TS_TX_OPCODE[2];
+ pseudo_bit_t TS_TX_SPEED[3];
+ pseudo_bit_t Reserved[16];
+ pseudo_bit_t TS_TX_TX_CFG[16];
+ pseudo_bit_t TS_TX_RX_CFG[16];
+};
+struct QIB_7220_IB_SDTEST_IF_TX {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_IB_SDTEST_IF_TX_pb );
+};
+
+#define QIB_7220_IB_SDTEST_IF_RX_offset 0x00000198UL
+struct QIB_7220_IB_SDTEST_IF_RX_pb {
+ pseudo_bit_t TS_T_RX_VALID[1];
+ pseudo_bit_t TS_3_RX_VALID[1];
+ pseudo_bit_t Reserved[14];
+ pseudo_bit_t TS_RX_A[8];
+ pseudo_bit_t TS_RX_B[8];
+ pseudo_bit_t TS_RX_TX_CFG[16];
+ pseudo_bit_t TS_RX_RX_CFG[16];
+};
+struct QIB_7220_IB_SDTEST_IF_RX {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_IB_SDTEST_IF_RX_pb );
+};
+
+#define QIB_7220_IBCDDRCtrl2_offset 0x000001a0UL
+struct QIB_7220_IBCDDRCtrl2_pb {
+ pseudo_bit_t IB_FRONT_PORCH[5];
+ pseudo_bit_t IB_BACK_PORCH[5];
+ pseudo_bit_t _unused_0[54];
+};
+struct QIB_7220_IBCDDRCtrl2 {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_IBCDDRCtrl2_pb );
+};
+
+#define QIB_7220_IBCDDRStatus_offset 0x000001a8UL
+struct QIB_7220_IBCDDRStatus_pb {
+ pseudo_bit_t LinkRoundTripLatency[26];
+ pseudo_bit_t ReqDDSLocalFromRmt[4];
+ pseudo_bit_t RxEqLocalDevice[2];
+ pseudo_bit_t heartbeat_crosstalk[4];
+ pseudo_bit_t heartbeat_timed_out[1];
+ pseudo_bit_t _unused_0[27];
+};
+struct QIB_7220_IBCDDRStatus {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_IBCDDRStatus_pb );
+};
+
+#define QIB_7220_JIntReload_offset 0x000001b0UL
+struct QIB_7220_JIntReload_pb {
+ pseudo_bit_t J_reload[16];
+ pseudo_bit_t J_limit_reload[16];
+ pseudo_bit_t _unused_0[32];
+};
+struct QIB_7220_JIntReload {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_JIntReload_pb );
+};
+
+#define QIB_7220_IBNCModeCtrl_offset 0x000001b8UL
+struct QIB_7220_IBNCModeCtrl_pb {
+ pseudo_bit_t TSMEnable_send_TS1[1];
+ pseudo_bit_t TSMEnable_send_TS2[1];
+ pseudo_bit_t TSMEnable_ignore_TSM_on_rx[1];
+ pseudo_bit_t Reserved1[5];
+ pseudo_bit_t TSMCode_TS1[9];
+ pseudo_bit_t TSMCode_TS2[9];
+ pseudo_bit_t Reserved[38];
+};
+struct QIB_7220_IBNCModeCtrl {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_IBNCModeCtrl_pb );
+};
+
+#define QIB_7220_SendCtrl_offset 0x000001c0UL
+struct QIB_7220_SendCtrl_pb {
+ pseudo_bit_t Abort[1];
+ pseudo_bit_t SendIntBufAvail[1];
+ pseudo_bit_t SendBufAvailUpd[1];
+ pseudo_bit_t SPioEnable[1];
+ pseudo_bit_t SSpecialTriggerEn[1];
+ pseudo_bit_t Reserved2[4];
+ pseudo_bit_t SDmaIntEnable[1];
+ pseudo_bit_t SDmaSingleDescriptor[1];
+ pseudo_bit_t SDmaEnable[1];
+ pseudo_bit_t SDmaHalt[1];
+ pseudo_bit_t Reserved1[3];
+ pseudo_bit_t DisarmPIOBuf[8];
+ pseudo_bit_t AvailUpdThld[5];
+ pseudo_bit_t Reserved[2];
+ pseudo_bit_t Disarm[1];
+ pseudo_bit_t _unused_0[32];
+};
+struct QIB_7220_SendCtrl {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_SendCtrl_pb );
+};
+
+#define QIB_7220_SendBufBase_offset 0x000001c8UL
+struct QIB_7220_SendBufBase_pb {
+ pseudo_bit_t BaseAddr_SmallPIO[21];
+ pseudo_bit_t Reserved1[11];
+ pseudo_bit_t BaseAddr_LargePIO[21];
+ pseudo_bit_t Reserved[11];
+};
+struct QIB_7220_SendBufBase {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_SendBufBase_pb );
+};
+
+#define QIB_7220_SendBufSize_offset 0x000001d0UL
+struct QIB_7220_SendBufSize_pb {
+ pseudo_bit_t Size_SmallPIO[12];
+ pseudo_bit_t Reserved1[20];
+ pseudo_bit_t Size_LargePIO[13];
+ pseudo_bit_t Reserved[19];
+};
+struct QIB_7220_SendBufSize {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_SendBufSize_pb );
+};
+
+#define QIB_7220_SendBufCnt_offset 0x000001d8UL
+struct QIB_7220_SendBufCnt_pb {
+ pseudo_bit_t Num_SmallBuffers[9];
+ pseudo_bit_t Reserved1[23];
+ pseudo_bit_t Num_LargeBuffers[4];
+ pseudo_bit_t Reserved[28];
+};
+struct QIB_7220_SendBufCnt {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_SendBufCnt_pb );
+};
+
+#define QIB_7220_SendBufAvailAddr_offset 0x000001e0UL
+struct QIB_7220_SendBufAvailAddr_pb {
+ pseudo_bit_t Reserved[6];
+ pseudo_bit_t SendBufAvailAddr[34];
+ pseudo_bit_t _unused_0[24];
+};
+struct QIB_7220_SendBufAvailAddr {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_SendBufAvailAddr_pb );
+};
+
+#define QIB_7220_TxIntMemBase_offset 0x000001e8UL
+
+#define QIB_7220_TxIntMemSize_offset 0x000001f0UL
+
+#define QIB_7220_SendDmaBase_offset 0x000001f8UL
+struct QIB_7220_SendDmaBase_pb {
+ pseudo_bit_t SendDmaBase[48];
+ pseudo_bit_t Reserved[16];
+};
+struct QIB_7220_SendDmaBase {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_SendDmaBase_pb );
+};
+
+#define QIB_7220_SendDmaLenGen_offset 0x00000200UL
+struct QIB_7220_SendDmaLenGen_pb {
+ pseudo_bit_t Length[16];
+ pseudo_bit_t Generation[3];
+ pseudo_bit_t Reserved[45];
+};
+struct QIB_7220_SendDmaLenGen {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_SendDmaLenGen_pb );
+};
+
+#define QIB_7220_SendDmaTail_offset 0x00000208UL
+struct QIB_7220_SendDmaTail_pb {
+ pseudo_bit_t SendDmaTail[16];
+ pseudo_bit_t Reserved[48];
+};
+struct QIB_7220_SendDmaTail {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_SendDmaTail_pb );
+};
+
+#define QIB_7220_SendDmaHead_offset 0x00000210UL
+struct QIB_7220_SendDmaHead_pb {
+ pseudo_bit_t SendDmaHead[16];
+ pseudo_bit_t Reserved1[16];
+ pseudo_bit_t InternalSendDmaHead[16];
+ pseudo_bit_t Reserved[16];
+};
+struct QIB_7220_SendDmaHead {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_SendDmaHead_pb );
+};
+
+#define QIB_7220_SendDmaHeadAddr_offset 0x00000218UL
+struct QIB_7220_SendDmaHeadAddr_pb {
+ pseudo_bit_t SendDmaHeadAddr[48];
+ pseudo_bit_t Reserved[16];
+};
+struct QIB_7220_SendDmaHeadAddr {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_SendDmaHeadAddr_pb );
+};
+
+#define QIB_7220_SendDmaBufMask0_offset 0x00000220UL
+struct QIB_7220_SendDmaBufMask0_pb {
+ pseudo_bit_t BufMask_63_0[0];
+ pseudo_bit_t _unused_0[64];
+};
+struct QIB_7220_SendDmaBufMask0 {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_SendDmaBufMask0_pb );
+};
+
+#define QIB_7220_SendDmaStatus_offset 0x00000238UL
+struct QIB_7220_SendDmaStatus_pb {
+ pseudo_bit_t SplFifoDescIndex[16];
+ pseudo_bit_t SplFifoBufNum[8];
+ pseudo_bit_t SplFifoFull[1];
+ pseudo_bit_t SplFifoEmpty[1];
+ pseudo_bit_t SplFifoDisarmed[1];
+ pseudo_bit_t SplFifoReadyToGo[1];
+ pseudo_bit_t ScbFetchDescFlag[1];
+ pseudo_bit_t ScbEntryValid[1];
+ pseudo_bit_t ScbEmpty[1];
+ pseudo_bit_t ScbFull[1];
+ pseudo_bit_t RpyTag_7_0[8];
+ pseudo_bit_t RpyLowAddr_6_0[7];
+ pseudo_bit_t ScbDescIndex_13_0[14];
+ pseudo_bit_t InternalSDmaEnable[1];
+ pseudo_bit_t AbortInProg[1];
+ pseudo_bit_t ScoreBoardDrainInProg[1];
+};
+struct QIB_7220_SendDmaStatus {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_SendDmaStatus_pb );
+};
+
+#define QIB_7220_SendBufErr0_offset 0x00000240UL
+struct QIB_7220_SendBufErr0_pb {
+ pseudo_bit_t SendBufErr_63_0[0];
+ pseudo_bit_t _unused_0[64];
+};
+struct QIB_7220_SendBufErr0 {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_SendBufErr0_pb );
+};
+
+#define QIB_7220_REG_000258_offset 0x00000258UL
+
+#define QIB_7220_AvailUpdCount_offset 0x00000268UL
+struct QIB_7220_AvailUpdCount_pb {
+ pseudo_bit_t AvailUpdCount[5];
+ pseudo_bit_t _unused_0[59];
+};
+struct QIB_7220_AvailUpdCount {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_AvailUpdCount_pb );
+};
+
+#define QIB_7220_RcvHdrAddr0_offset 0x00000270UL
+struct QIB_7220_RcvHdrAddr0_pb {
+ pseudo_bit_t Reserved[2];
+ pseudo_bit_t RcvHdrAddr0[38];
+ pseudo_bit_t _unused_0[24];
+};
+struct QIB_7220_RcvHdrAddr0 {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrAddr0_pb );
+};
+
+#define QIB_7220_REG_0002F8_offset 0x000002f8UL
+
+#define QIB_7220_RcvHdrTailAddr0_offset 0x00000300UL
+struct QIB_7220_RcvHdrTailAddr0_pb {
+ pseudo_bit_t Reserved[2];
+ pseudo_bit_t RcvHdrTailAddr0[38];
+ pseudo_bit_t _unused_0[24];
+};
+struct QIB_7220_RcvHdrTailAddr0 {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrTailAddr0_pb );
+};
+
+#define QIB_7220_REG_000388_offset 0x00000388UL
+
+#define QIB_7220_ibsd_epb_access_ctrl_offset 0x000003c0UL
+struct QIB_7220_ibsd_epb_access_ctrl_pb {
+ pseudo_bit_t sw_ib_epb_req[1];
+ pseudo_bit_t Reserved[7];
+ pseudo_bit_t sw_ib_epb_req_granted[1];
+ pseudo_bit_t _unused_0[55];
+};
+struct QIB_7220_ibsd_epb_access_ctrl {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_ibsd_epb_access_ctrl_pb );
+};
+
+#define QIB_7220_ibsd_epb_transaction_reg_offset 0x000003c8UL
+struct QIB_7220_ibsd_epb_transaction_reg_pb {
+ pseudo_bit_t ib_epb_data[8];
+ pseudo_bit_t ib_epb_address[15];
+ pseudo_bit_t Reserved2[1];
+ pseudo_bit_t ib_epb_read_write[1];
+ pseudo_bit_t ib_epb_cs[2];
+ pseudo_bit_t Reserved1[1];
+ pseudo_bit_t mem_data_parity[1];
+ pseudo_bit_t Reserved[1];
+ pseudo_bit_t ib_epb_req_error[1];
+ pseudo_bit_t ib_epb_rdy[1];
+ pseudo_bit_t _unused_0[32];
+};
+struct QIB_7220_ibsd_epb_transaction_reg {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_ibsd_epb_transaction_reg_pb );
+};
+
+#define QIB_7220_REG_0003D0_offset 0x000003d0UL
+
+#define QIB_7220_XGXSCfg_offset 0x000003d8UL
+struct QIB_7220_XGXSCfg_pb {
+ pseudo_bit_t tx_rx_reset[1];
+ pseudo_bit_t Reserved2[1];
+ pseudo_bit_t xcv_reset[1];
+ pseudo_bit_t Reserved1[6];
+ pseudo_bit_t link_sync_mask[10];
+ pseudo_bit_t Reserved[44];
+ pseudo_bit_t sel_link_down_for_fctrl_lane_sync_reset[1];
+};
+struct QIB_7220_XGXSCfg {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_XGXSCfg_pb );
+};
+
+#define QIB_7220_IBSerDesCtrl_offset 0x000003e0UL
+struct QIB_7220_IBSerDesCtrl_pb {
+ pseudo_bit_t ResetIB_uC_Core[1];
+ pseudo_bit_t Reserved2[7];
+ pseudo_bit_t NumSerDesRegsToWrForDDS[5];
+ pseudo_bit_t NumSerDesRegsToWrForRXEQ[5];
+ pseudo_bit_t Reserved1[14];
+ pseudo_bit_t TXINV[1];
+ pseudo_bit_t RXINV[1];
+ pseudo_bit_t RXIDLE[1];
+ pseudo_bit_t TWC[1];
+ pseudo_bit_t TXOBPD[1];
+ pseudo_bit_t PLLM[3];
+ pseudo_bit_t PLLN[2];
+ pseudo_bit_t CKSEL_uC[2];
+ pseudo_bit_t INT_uC[1];
+ pseudo_bit_t Reserved[19];
+};
+struct QIB_7220_IBSerDesCtrl {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_IBSerDesCtrl_pb );
+};
+
+#define QIB_7220_EEPCtlStat_offset 0x000003e8UL
+struct QIB_7220_EEPCtlStat_pb {
+ pseudo_bit_t EPAccEn[2];
+ pseudo_bit_t EPReset[1];
+ pseudo_bit_t ByteProg[1];
+ pseudo_bit_t PageMode[1];
+ pseudo_bit_t LstDatWr[1];
+ pseudo_bit_t CmdWrErr[1];
+ pseudo_bit_t Reserved[24];
+ pseudo_bit_t CtlrStat[1];
+ pseudo_bit_t _unused_0[32];
+};
+struct QIB_7220_EEPCtlStat {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_EEPCtlStat_pb );
+};
+
+#define QIB_7220_EEPAddrCmd_offset 0x000003f0UL
+struct QIB_7220_EEPAddrCmd_pb {
+ pseudo_bit_t EPAddr[24];
+ pseudo_bit_t EPCmd[8];
+ pseudo_bit_t _unused_0[32];
+};
+struct QIB_7220_EEPAddrCmd {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_EEPAddrCmd_pb );
+};
+
+#define QIB_7220_EEPData_offset 0x000003f8UL
+
+#define QIB_7220_pciesd_epb_access_ctrl_offset 0x00000400UL
+struct QIB_7220_pciesd_epb_access_ctrl_pb {
+ pseudo_bit_t sw_pcie_epb_req[1];
+ pseudo_bit_t sw_pcieepb_star_en[2];
+ pseudo_bit_t Reserved[5];
+ pseudo_bit_t sw_pcie_epb_req_granted[1];
+ pseudo_bit_t _unused_0[55];
+};
+struct QIB_7220_pciesd_epb_access_ctrl {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_pciesd_epb_access_ctrl_pb );
+};
+
+#define QIB_7220_pciesd_epb_transaction_reg_offset 0x00000408UL
+struct QIB_7220_pciesd_epb_transaction_reg_pb {
+ pseudo_bit_t pcie_epb_data[8];
+ pseudo_bit_t pcie_epb_address[15];
+ pseudo_bit_t Reserved1[1];
+ pseudo_bit_t pcie_epb_read_write[1];
+ pseudo_bit_t pcie_epb_cs[3];
+ pseudo_bit_t mem_data_parity[1];
+ pseudo_bit_t Reserved[1];
+ pseudo_bit_t pcie_epb_req_error[1];
+ pseudo_bit_t pcie_epb_rdy[1];
+ pseudo_bit_t _unused_0[32];
+};
+struct QIB_7220_pciesd_epb_transaction_reg {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_pciesd_epb_transaction_reg_pb );
+};
+
+#define QIB_7220_efuse_control_reg_offset 0x00000410UL
+struct QIB_7220_efuse_control_reg_pb {
+ pseudo_bit_t start_op[1];
+ pseudo_bit_t operation[1];
+ pseudo_bit_t read_valid[1];
+ pseudo_bit_t req_error[1];
+ pseudo_bit_t Reserved[27];
+ pseudo_bit_t rdy[1];
+ pseudo_bit_t _unused_0[32];
+};
+struct QIB_7220_efuse_control_reg {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_efuse_control_reg_pb );
+};
+
+#define QIB_7220_efuse_rddata0_reg_offset 0x00000418UL
+
+#define QIB_7220_procmon_register_offset 0x00000438UL
+struct QIB_7220_procmon_register_pb {
+ pseudo_bit_t interval_time[12];
+ pseudo_bit_t Reserved1[2];
+ pseudo_bit_t clear_counter[1];
+ pseudo_bit_t start_counter[1];
+ pseudo_bit_t procmon_count[9];
+ pseudo_bit_t Reserved[6];
+ pseudo_bit_t procmon_count_valid[1];
+ pseudo_bit_t _unused_0[32];
+};
+struct QIB_7220_procmon_register {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_procmon_register_pb );
+};
+
+#define QIB_7220_PcieRbufTestReg0_offset 0x00000440UL
+
+#define QIB_7220_PcieRBufTestReg1_offset 0x00000448UL
+
+#define QIB_7220_SPC_JTAG_ACCESS_REG_offset 0x00000460UL
+struct QIB_7220_SPC_JTAG_ACCESS_REG_pb {
+ pseudo_bit_t rdy[1];
+ pseudo_bit_t tdo[1];
+ pseudo_bit_t tdi[1];
+ pseudo_bit_t opcode[2];
+ pseudo_bit_t bist_en[5];
+ pseudo_bit_t SPC_JTAG_ACCESS_EN[1];
+ pseudo_bit_t _unused_0[53];
+};
+struct QIB_7220_SPC_JTAG_ACCESS_REG {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_SPC_JTAG_ACCESS_REG_pb );
+};
+
+#define QIB_7220_LAControlReg_offset 0x00000468UL
+struct QIB_7220_LAControlReg_pb {
+ pseudo_bit_t Finished[1];
+ pseudo_bit_t Address[8];
+ pseudo_bit_t Mode[2];
+ pseudo_bit_t Delay[20];
+ pseudo_bit_t Reserved[1];
+ pseudo_bit_t _unused_0[32];
+};
+struct QIB_7220_LAControlReg {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_LAControlReg_pb );
+};
+
+#define QIB_7220_GPIODebugSelReg_offset 0x00000470UL
+struct QIB_7220_GPIODebugSelReg_pb {
+ pseudo_bit_t GPIOSourceSelDebug[16];
+ pseudo_bit_t SelPulse[16];
+ pseudo_bit_t _unused_0[32];
+};
+struct QIB_7220_GPIODebugSelReg {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_GPIODebugSelReg_pb );
+};
+
+#define QIB_7220_DebugPortValueReg_offset 0x00000478UL
+
+#define QIB_7220_SendDmaBufUsed0_offset 0x00000480UL
+struct QIB_7220_SendDmaBufUsed0_pb {
+ pseudo_bit_t BufUsed_63_0[0];
+ pseudo_bit_t _unused_0[64];
+};
+struct QIB_7220_SendDmaBufUsed0 {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_SendDmaBufUsed0_pb );
+};
+
+#define QIB_7220_SendDmaReqTagUsed_offset 0x00000498UL
+struct QIB_7220_SendDmaReqTagUsed_pb {
+ pseudo_bit_t ReqTagUsed_7_0[8];
+ pseudo_bit_t _unused_0[8];
+ pseudo_bit_t Reserved[48];
+ pseudo_bit_t _unused_1[8];
+};
+struct QIB_7220_SendDmaReqTagUsed {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_SendDmaReqTagUsed_pb );
+};
+
+#define QIB_7220_efuse_pgm_data0_offset 0x000004a0UL
+
+#define QIB_7220_MEM_0004B0_offset 0x000004b0UL
+
+#define QIB_7220_SerDes_DDSRXEQ0_offset 0x00000500UL
+struct QIB_7220_SerDes_DDSRXEQ0_pb {
+ pseudo_bit_t element_num[4];
+ pseudo_bit_t reg_addr[6];
+ pseudo_bit_t _unused_0[54];
+};
+struct QIB_7220_SerDes_DDSRXEQ0 {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_SerDes_DDSRXEQ0_pb );
+};
+
+#define QIB_7220_MEM_0005F0_offset 0x000005f0UL
+
+#define QIB_7220_LAMemory_offset 0x00000600UL
+
+#define QIB_7220_MEM_0007F0_offset 0x000007f0UL
+
+#define QIB_7220_SendBufAvail0_offset 0x00001000UL
+struct QIB_7220_SendBufAvail0_pb {
+ pseudo_bit_t SendBuf_31_0[0];
+ pseudo_bit_t _unused_0[64];
+};
+struct QIB_7220_SendBufAvail0 {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_SendBufAvail0_pb );
+};
+
+#define QIB_7220_MEM_001028_offset 0x00001028UL
+
+#define QIB_7220_LBIntCnt_offset 0x00013000UL
+
+#define QIB_7220_LBFlowStallCnt_offset 0x00013008UL
+
+#define QIB_7220_TxSDmaDescCnt_offset 0x00013010UL
+
+#define QIB_7220_TxUnsupVLErrCnt_offset 0x00013018UL
+
+#define QIB_7220_TxDataPktCnt_offset 0x00013020UL
+
+#define QIB_7220_TxFlowPktCnt_offset 0x00013028UL
+
+#define QIB_7220_TxDwordCnt_offset 0x00013030UL
+
+#define QIB_7220_TxLenErrCnt_offset 0x00013038UL
+
+#define QIB_7220_TxMaxMinLenErrCnt_offset 0x00013040UL
+
+#define QIB_7220_TxUnderrunCnt_offset 0x00013048UL
+
+#define QIB_7220_TxFlowStallCnt_offset 0x00013050UL
+
+#define QIB_7220_TxDroppedPktCnt_offset 0x00013058UL
+
+#define QIB_7220_RxDroppedPktCnt_offset 0x00013060UL
+
+#define QIB_7220_RxDataPktCnt_offset 0x00013068UL
+
+#define QIB_7220_RxFlowPktCnt_offset 0x00013070UL
+
+#define QIB_7220_RxDwordCnt_offset 0x00013078UL
+
+#define QIB_7220_RxLenErrCnt_offset 0x00013080UL
+
+#define QIB_7220_RxMaxMinLenErrCnt_offset 0x00013088UL
+
+#define QIB_7220_RxICRCErrCnt_offset 0x00013090UL
+
+#define QIB_7220_RxVCRCErrCnt_offset 0x00013098UL
+
+#define QIB_7220_RxFlowCtrlViolCnt_offset 0x000130a0UL
+
+#define QIB_7220_RxVersionErrCnt_offset 0x000130a8UL
+
+#define QIB_7220_RxLinkMalformCnt_offset 0x000130b0UL
+
+#define QIB_7220_RxEBPCnt_offset 0x000130b8UL
+
+#define QIB_7220_RxLPCRCErrCnt_offset 0x000130c0UL
+
+#define QIB_7220_RxBufOvflCnt_offset 0x000130c8UL
+
+#define QIB_7220_RxTIDFullErrCnt_offset 0x000130d0UL
+
+#define QIB_7220_RxTIDValidErrCnt_offset 0x000130d8UL
+
+#define QIB_7220_RxPKeyMismatchCnt_offset 0x000130e0UL
+
+#define QIB_7220_RxP0HdrEgrOvflCnt_offset 0x000130e8UL
+
+#define QIB_7220_IBStatusChangeCnt_offset 0x00013170UL
+
+#define QIB_7220_IBLinkErrRecoveryCnt_offset 0x00013178UL
+
+#define QIB_7220_IBLinkDownedCnt_offset 0x00013180UL
+
+#define QIB_7220_IBSymbolErrCnt_offset 0x00013188UL
+
+#define QIB_7220_RxVL15DroppedPktCnt_offset 0x00013190UL
+
+#define QIB_7220_RxOtherLocalPhyErrCnt_offset 0x00013198UL
+
+#define QIB_7220_PcieRetryBufDiagQwordCnt_offset 0x000131a0UL
+
+#define QIB_7220_ExcessBufferOvflCnt_offset 0x000131a8UL
+
+#define QIB_7220_LocalLinkIntegrityErrCnt_offset 0x000131b0UL
+
+#define QIB_7220_RxVlErrCnt_offset 0x000131b8UL
+
+#define QIB_7220_RxDlidFltrCnt_offset 0x000131c0UL
+
+#define QIB_7220_CNT_0131C8_offset 0x000131c8UL
+
+#define QIB_7220_PSStat_offset 0x00013200UL
+
+#define QIB_7220_PSStart_offset 0x00013208UL
+
+#define QIB_7220_PSInterval_offset 0x00013210UL
+
+#define QIB_7220_PSRcvDataCount_offset 0x00013218UL
+
+#define QIB_7220_PSRcvPktsCount_offset 0x00013220UL
+
+#define QIB_7220_PSXmitDataCount_offset 0x00013228UL
+
+#define QIB_7220_PSXmitPktsCount_offset 0x00013230UL
+
+#define QIB_7220_PSXmitWaitCount_offset 0x00013238UL
+
+#define QIB_7220_CNT_013240_offset 0x00013240UL
+
+#define QIB_7220_RcvEgrArray_offset 0x00014000UL
+
+#define QIB_7220_MEM_038000_offset 0x00038000UL
+
+#define QIB_7220_RcvTIDArray0_offset 0x00053000UL
+
+#define QIB_7220_PIOLaunchFIFO_offset 0x00064000UL
+
+#define QIB_7220_MEM_064480_offset 0x00064480UL
+
+#define QIB_7220_SendPIOpbcCache_offset 0x00064800UL
+
+#define QIB_7220_MEM_064C80_offset 0x00064c80UL
+
+#define QIB_7220_PreLaunchFIFO_offset 0x00065000UL
+
+#define QIB_7220_MEM_065080_offset 0x00065080UL
+
+#define QIB_7220_ScoreBoard_offset 0x00065400UL
+
+#define QIB_7220_MEM_065440_offset 0x00065440UL
+
+#define QIB_7220_DescriptorFIFO_offset 0x00065800UL
+
+#define QIB_7220_MEM_065880_offset 0x00065880UL
+
+#define QIB_7220_RcvBuf1_offset 0x00072000UL
+
+#define QIB_7220_MEM_074800_offset 0x00074800UL
+
+#define QIB_7220_RcvBuf2_offset 0x00075000UL
+
+#define QIB_7220_MEM_076400_offset 0x00076400UL
+
+#define QIB_7220_RcvFlags_offset 0x00077000UL
+
+#define QIB_7220_MEM_078400_offset 0x00078400UL
+
+#define QIB_7220_RcvLookupBuf1_offset 0x00079000UL
+
+#define QIB_7220_MEM_07A400_offset 0x0007a400UL
+
+#define QIB_7220_RcvDMADatBuf_offset 0x0007b000UL
+
+#define QIB_7220_RcvDMAHdrBuf_offset 0x0007b800UL
+
+#define QIB_7220_MiscRXEIntMem_offset 0x0007c000UL
+
+#define QIB_7220_MEM_07D400_offset 0x0007d400UL
+
+#define QIB_7220_PCIERcvBuf_offset 0x00080000UL
+
+#define QIB_7220_PCIERetryBuf_offset 0x00084000UL
+
+#define QIB_7220_PCIERcvBufRdToWrAddr_offset 0x00088000UL
+
+#define QIB_7220_PCIECplBuf_offset 0x00090000UL
+
+#define QIB_7220_IBSerDesMappTable_offset 0x00094000UL
+
+#define QIB_7220_MEM_095000_offset 0x00095000UL
+
+#define QIB_7220_SendBuf0_MA_offset 0x00100000UL
+
+#define QIB_7220_MEM_1A0000_offset 0x001a0000UL
+
+#define QIB_7220_RcvHdrTail0_offset 0x00200000UL
+
+#define QIB_7220_RcvHdrHead0_offset 0x00200008UL
+struct QIB_7220_RcvHdrHead0_pb {
+ pseudo_bit_t RcvHeadPointer[32];
+ pseudo_bit_t counter[16];
+ pseudo_bit_t Reserved[16];
+};
+struct QIB_7220_RcvHdrHead0 {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead0_pb );
+};
+
+#define QIB_7220_RcvEgrIndexTail0_offset 0x00200010UL
+
+#define QIB_7220_RcvEgrIndexHead0_offset 0x00200018UL
+
+#define QIB_7220_MEM_200020_offset 0x00200020UL
+
+#define QIB_7220_RcvHdrTail1_offset 0x00210000UL
+
+#define QIB_7220_RcvHdrHead1_offset 0x00210008UL
+struct QIB_7220_RcvHdrHead1_pb {
+ pseudo_bit_t RcvHeadPointer[32];
+ pseudo_bit_t counter[16];
+ pseudo_bit_t Reserved[16];
+};
+struct QIB_7220_RcvHdrHead1 {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead1_pb );
+};
+
+#define QIB_7220_RcvEgrIndexTail1_offset 0x00210010UL
+
+#define QIB_7220_RcvEgrIndexHead1_offset 0x00210018UL
+
+#define QIB_7220_MEM_210020_offset 0x00210020UL
+
+#define QIB_7220_RcvHdrTail2_offset 0x00220000UL
+
+#define QIB_7220_RcvHdrHead2_offset 0x00220008UL
+struct QIB_7220_RcvHdrHead2_pb {
+ pseudo_bit_t RcvHeadPointer[32];
+ pseudo_bit_t counter[16];
+ pseudo_bit_t Reserved[16];
+};
+struct QIB_7220_RcvHdrHead2 {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead2_pb );
+};
+
+#define QIB_7220_RcvEgrIndexTail2_offset 0x00220010UL
+
+#define QIB_7220_RcvEgrIndexHead2_offset 0x00220018UL
+
+#define QIB_7220_MEM_220020_offset 0x00220020UL
+
+#define QIB_7220_RcvHdrTail3_offset 0x00230000UL
+
+#define QIB_7220_RcvHdrHead3_offset 0x00230008UL
+struct QIB_7220_RcvHdrHead3_pb {
+ pseudo_bit_t RcvHeadPointer[32];
+ pseudo_bit_t counter[16];
+ pseudo_bit_t Reserved[16];
+};
+struct QIB_7220_RcvHdrHead3 {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead3_pb );
+};
+
+#define QIB_7220_RcvEgrIndexTail3_offset 0x00230010UL
+
+#define QIB_7220_RcvEgrIndexHead3_offset 0x00230018UL
+
+#define QIB_7220_MEM_230020_offset 0x00230020UL
+
+#define QIB_7220_RcvHdrTail4_offset 0x00240000UL
+
+#define QIB_7220_RcvHdrHead4_offset 0x00240008UL
+struct QIB_7220_RcvHdrHead4_pb {
+ pseudo_bit_t RcvHeadPointer[32];
+ pseudo_bit_t counter[16];
+ pseudo_bit_t Reserved[16];
+};
+struct QIB_7220_RcvHdrHead4 {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead4_pb );
+};
+
+#define QIB_7220_RcvEgrIndexTail4_offset 0x00240010UL
+
+#define QIB_7220_RcvEgrIndexHead4_offset 0x00240018UL
+
+#define QIB_7220_MEM_240020_offset 0x00240020UL
+
+#define QIB_7220_RcvHdrTail5_offset 0x00250000UL
+
+#define QIB_7220_RcvHdrHead5_offset 0x00250008UL
+struct QIB_7220_RcvHdrHead5_pb {
+ pseudo_bit_t RcvHeadPointer[32];
+ pseudo_bit_t counter[16];
+ pseudo_bit_t Reserved[16];
+};
+struct QIB_7220_RcvHdrHead5 {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead5_pb );
+};
+
+#define QIB_7220_RcvEgrIndexTail5_offset 0x00250010UL
+
+#define QIB_7220_RcvEgrIndexHead5_offset 0x00250018UL
+
+#define QIB_7220_MEM_250020_offset 0x00250020UL
+
+#define QIB_7220_RcvHdrTail6_offset 0x00260000UL
+
+#define QIB_7220_RcvHdrHead6_offset 0x00260008UL
+struct QIB_7220_RcvHdrHead6_pb {
+ pseudo_bit_t RcvHeadPointer[32];
+ pseudo_bit_t counter[16];
+ pseudo_bit_t Reserved[16];
+};
+struct QIB_7220_RcvHdrHead6 {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead6_pb );
+};
+
+#define QIB_7220_RcvEgrIndexTail6_offset 0x00260010UL
+
+#define QIB_7220_RcvEgrIndexHead6_offset 0x00260018UL
+
+#define QIB_7220_MEM_260020_offset 0x00260020UL
+
+#define QIB_7220_RcvHdrTail7_offset 0x00270000UL
+
+#define QIB_7220_RcvHdrHead7_offset 0x00270008UL
+struct QIB_7220_RcvHdrHead7_pb {
+ pseudo_bit_t RcvHeadPointer[32];
+ pseudo_bit_t counter[16];
+ pseudo_bit_t Reserved[16];
+};
+struct QIB_7220_RcvHdrHead7 {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead7_pb );
+};
+
+#define QIB_7220_RcvEgrIndexTail7_offset 0x00270010UL
+
+#define QIB_7220_RcvEgrIndexHead7_offset 0x00270018UL
+
+#define QIB_7220_MEM_270020_offset 0x00270020UL
+
+#define QIB_7220_RcvHdrTail8_offset 0x00280000UL
+
+#define QIB_7220_RcvHdrHead8_offset 0x00280008UL
+struct QIB_7220_RcvHdrHead8_pb {
+ pseudo_bit_t RcvHeadPointer[32];
+ pseudo_bit_t counter[16];
+ pseudo_bit_t Reserved[16];
+};
+struct QIB_7220_RcvHdrHead8 {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead8_pb );
+};
+
+#define QIB_7220_RcvEgrIndexTail8_offset 0x00280010UL
+
+#define QIB_7220_RcvEgrIndexHead8_offset 0x00280018UL
+
+#define QIB_7220_MEM_280020_offset 0x00280020UL
+
+#define QIB_7220_RcvHdrTail9_offset 0x00290000UL
+
+#define QIB_7220_RcvHdrHead9_offset 0x00290008UL
+struct QIB_7220_RcvHdrHead9_pb {
+ pseudo_bit_t RcvHeadPointer[32];
+ pseudo_bit_t counter[16];
+ pseudo_bit_t Reserved[16];
+};
+struct QIB_7220_RcvHdrHead9 {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead9_pb );
+};
+
+#define QIB_7220_RcvEgrIndexTail9_offset 0x00290010UL
+
+#define QIB_7220_RcvEgrIndexHead9_offset 0x00290018UL
+
+#define QIB_7220_MEM_290020_offset 0x00290020UL
+
+#define QIB_7220_RcvHdrTail10_offset 0x002a0000UL
+
+#define QIB_7220_RcvHdrHead10_offset 0x002a0008UL
+struct QIB_7220_RcvHdrHead10_pb {
+ pseudo_bit_t RcvHeadPointer[32];
+ pseudo_bit_t counter[16];
+ pseudo_bit_t Reserved[16];
+};
+struct QIB_7220_RcvHdrHead10 {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead10_pb );
+};
+
+#define QIB_7220_RcvEgrIndexTail10_offset 0x002a0010UL
+
+#define QIB_7220_RcvEgrIndexHead10_offset 0x002a0018UL
+
+#define QIB_7220_MEM_2A0020_offset 0x002a0020UL
+
+#define QIB_7220_RcvHdrTail11_offset 0x002b0000UL
+
+#define QIB_7220_RcvHdrHead11_offset 0x002b0008UL
+struct QIB_7220_RcvHdrHead11_pb {
+ pseudo_bit_t RcvHeadPointer[32];
+ pseudo_bit_t counter[16];
+ pseudo_bit_t Reserved[16];
+};
+struct QIB_7220_RcvHdrHead11 {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead11_pb );
+};
+
+#define QIB_7220_RcvEgrIndexTail11_offset 0x002b0010UL
+
+#define QIB_7220_RcvEgrIndexHead11_offset 0x002b0018UL
+
+#define QIB_7220_MEM_2B0020_offset 0x002b0020UL
+
+#define QIB_7220_RcvHdrTail12_offset 0x002c0000UL
+
+#define QIB_7220_RcvHdrHead12_offset 0x002c0008UL
+struct QIB_7220_RcvHdrHead12_pb {
+ pseudo_bit_t RcvHeadPointer[32];
+ pseudo_bit_t counter[16];
+ pseudo_bit_t Reserved[16];
+};
+struct QIB_7220_RcvHdrHead12 {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead12_pb );
+};
+
+#define QIB_7220_RcvEgrIndexTail12_offset 0x002c0010UL
+
+#define QIB_7220_RcvEgrIndexHead12_offset 0x002c0018UL
+
+#define QIB_7220_MEM_2C0020_offset 0x002c0020UL
+
+#define QIB_7220_RcvHdrTail13_offset 0x002d0000UL
+
+#define QIB_7220_RcvHdrHead13_offset 0x002d0008UL
+struct QIB_7220_RcvHdrHead13_pb {
+ pseudo_bit_t RcvHeadPointer[32];
+ pseudo_bit_t counter[16];
+ pseudo_bit_t Reserved[16];
+};
+struct QIB_7220_RcvHdrHead13 {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead13_pb );
+};
+
+#define QIB_7220_RcvEgrIndexTail13_offset 0x002d0010UL
+
+#define QIB_7220_RcvEgrIndexHead13_offset 0x002d0018UL
+
+#define QIB_7220_MEM_2D0020_offset 0x002d0020UL
+
+#define QIB_7220_RcvHdrTail14_offset 0x002e0000UL
+
+#define QIB_7220_RcvHdrHead14_offset 0x002e0008UL
+struct QIB_7220_RcvHdrHead14_pb {
+ pseudo_bit_t RcvHeadPointer[32];
+ pseudo_bit_t counter[16];
+ pseudo_bit_t Reserved[16];
+};
+struct QIB_7220_RcvHdrHead14 {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead14_pb );
+};
+
+#define QIB_7220_RcvEgrIndexTail14_offset 0x002e0010UL
+
+#define QIB_7220_RcvEgrIndexHead14_offset 0x002e0018UL
+
+#define QIB_7220_MEM_2E0020_offset 0x002e0020UL
+
+#define QIB_7220_RcvHdrTail15_offset 0x002f0000UL
+
+#define QIB_7220_RcvHdrHead15_offset 0x002f0008UL
+struct QIB_7220_RcvHdrHead15_pb {
+ pseudo_bit_t RcvHeadPointer[32];
+ pseudo_bit_t counter[16];
+ pseudo_bit_t Reserved[16];
+};
+struct QIB_7220_RcvHdrHead15 {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead15_pb );
+};
+
+#define QIB_7220_RcvEgrIndexTail15_offset 0x002f0010UL
+
+#define QIB_7220_RcvEgrIndexHead15_offset 0x002f0018UL
+
+#define QIB_7220_MEM_2F0020_offset 0x002f0020UL
+
+#define QIB_7220_RcvHdrTail16_offset 0x00300000UL
+
+#define QIB_7220_RcvHdrHead16_offset 0x00300008UL
+struct QIB_7220_RcvHdrHead16_pb {
+ pseudo_bit_t RcvHeadPointer[32];
+ pseudo_bit_t counter[16];
+ pseudo_bit_t Reserved[16];
+};
+struct QIB_7220_RcvHdrHead16 {
+ PSEUDO_BIT_STRUCT ( struct QIB_7220_RcvHdrHead16_pb );
+};
+
+#define QIB_7220_RcvEgrIndexTail16_offset 0x00300010UL
+
+#define QIB_7220_RcvEgrIndexHead16_offset 0x00300018UL
+
+#define QIB_7220_MEM_300020_offset 0x00300020UL
+
diff --git a/gpxe/src/drivers/infiniband/qib_genbits.pl b/gpxe/src/drivers/infiniband/qib_genbits.pl
new file mode 100644
index 00000000..9eba4da5
--- /dev/null
+++ b/gpxe/src/drivers/infiniband/qib_genbits.pl
@@ -0,0 +1,95 @@
+#!/usr/bin/perl -w
+#
+# Copyright (C) 2008 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.
+
+use strict;
+use warnings;
+
+my $offsets = {};
+my $structures = {};
+my $structure = "";
+
+while ( <> ) {
+ chomp;
+ if ( /^\#define (\S+)_OFFS (\S+)$/ ) {
+ $structure = $1;
+ $offsets->{$structure} = $2;
+ } elsif ( /^\#define ${structure}_(\S+)_LSB (\S+)$/ ) {
+ $structures->{$structure}->{$1}->{LSB} = $2;
+ } elsif ( /^\#define ${structure}_(\S+)_RMASK (\S+)$/ ) {
+ $structures->{$structure}->{$1}->{RMASK} = $2;
+ } elsif ( /^\s*$/ ) {
+ # Do nothing
+ } else {
+ print "$_\n";
+ }
+}
+
+my $data = [ map { { name => $_, offset => $offsets->{$_} }; }
+ sort { hex ( $offsets->{$a} ) <=> hex ( $offsets->{$b} ) }
+ keys %$offsets ];
+
+foreach my $datum ( @$data ) {
+ next unless exists $structures->{$datum->{name}};
+ $structure = $structures->{$datum->{name}};
+ my $fields = [ map { { name => $_, lsb => $structure->{$_}->{LSB},
+ rmask => $structure->{$_}->{RMASK} }; }
+ sort { hex ( $structure->{$a}->{LSB} ) <=>
+ hex ( $structure->{$b}->{LSB} ) }
+ keys %$structure ];
+ $datum->{fields} = $fields;
+}
+
+print "\n/* This file has been further processed by $0 */\n\n\n";
+
+foreach my $datum ( @$data ) {
+ printf "#define %s_offset 0x%08xUL\n",
+ $datum->{name}, hex ( $datum->{offset} );
+ if ( exists $datum->{fields} ) {
+ my $lsb = 0;
+ my $reserved_idx = 0;
+ printf "struct %s_pb {\n", $datum->{name};
+ foreach my $field ( @{$datum->{fields}} ) {
+ my $pad_width = ( hex ( $field->{lsb} ) - $lsb );
+ die "Inconsistent LSB/RMASK in $datum->{name}\n" if $pad_width < 0;
+ printf "\tpseudo_bit_t _unused_%u[%u];\n", $reserved_idx++, $pad_width
+ if $pad_width;
+ # Damn Perl can't cope with 64-bit hex constants
+ my $width = 0;
+ my $rmask = $field->{rmask};
+ while ( $rmask =~ /^(0x.+)f$/i ) {
+ $width += 4;
+ $rmask = $1;
+ }
+ $rmask = hex ( $rmask );
+ while ( $rmask ) {
+ $width++;
+ $rmask >>= 1;
+ }
+ printf "\tpseudo_bit_t %s[%u];\n", $field->{name}, $width;
+ $lsb += $width;
+ }
+ my $pad_width = ( 64 - $lsb );
+ die "Inconsistent LSB/RMASK in $datum->{name}\n" if $pad_width < 0;
+ printf "\tpseudo_bit_t _unused_%u[%u];\n", $reserved_idx++, $pad_width
+ if $pad_width;
+ printf "};\n";
+ printf "struct %s {\n\tPSEUDO_BIT_STRUCT ( struct %s_pb );\n};\n",
+ $datum->{name}, $datum->{name};
+ }
+ print "\n";
+}
diff --git a/gpxe/src/drivers/net/3c509.c b/gpxe/src/drivers/net/3c509.c
index 8a15aff2..ecfdec55 100644
--- a/gpxe/src/drivers/net/3c509.c
+++ b/gpxe/src/drivers/net/3c509.c
@@ -8,7 +8,7 @@
#include <stdlib.h>
#include <string.h>
#include <errno.h>
-#include <io.h>
+#include <gpxe/io.h>
#include <unistd.h>
#include <gpxe/device.h>
#include <gpxe/isa.h>
diff --git a/gpxe/src/drivers/net/3c595.c b/gpxe/src/drivers/net/3c595.c
index 7138f936..198e12e7 100644
--- a/gpxe/src/drivers/net/3c595.c
+++ b/gpxe/src/drivers/net/3c595.c
@@ -363,7 +363,7 @@ vxgetlink(void)
if (n > 0) {
printf("/");
}
- printf(conn_tab[k].name);
+ printf("%s", conn_tab[k].name );
n++;
}
}
diff --git a/gpxe/src/drivers/net/3c90x.c b/gpxe/src/drivers/net/3c90x.c
index 8158239d..a98e6628 100644
--- a/gpxe/src/drivers/net/3c90x.c
+++ b/gpxe/src/drivers/net/3c90x.c
@@ -497,7 +497,7 @@ a3c90x_transmit(struct nic *nic __unused, const char *d, unsigned int t,
unsigned char status;
unsigned i, retries;
- tick_t ct;
+ unsigned long ct;
for (retries=0; retries < XMIT_RETRIES ; retries++)
{
@@ -543,7 +543,7 @@ a3c90x_transmit(struct nic *nic __unused, const char *d, unsigned int t,
ct = currticks();
while (!(inw(INF_3C90X.IOAddr + regCommandIntStatus_w)&0x0004) &&
- ct + 10*USECS_IN_MSEC < currticks());
+ ct + 10*1000 < currticks());
;
if (!(inw(INF_3C90X.IOAddr + regCommandIntStatus_w)&0x0004))
diff --git a/gpxe/src/drivers/net/cs89x0.c b/gpxe/src/drivers/net/cs89x0.c
index 11988add..1f647a8e 100644
--- a/gpxe/src/drivers/net/cs89x0.c
+++ b/gpxe/src/drivers/net/cs89x0.c
@@ -419,8 +419,8 @@ retry:
ETH_ALEN/2);
outw(((t >> 8)&0xFF)|(t << 8), eth_nic_base + TX_FRAME_PORT);
outsw(eth_nic_base + TX_FRAME_PORT, p, (s+1)/2);
- for (sr = sr/2 - (s+1)/2 - ETH_ALEN - 1; sr-- > 0;
- outw(0, eth_nic_base + TX_FRAME_PORT));
+ for (sr = sr/2 - (s+1)/2 - ETH_ALEN - 1; sr > 0; sr--)
+ outw(0, eth_nic_base + TX_FRAME_PORT);
/* wait for transfer to succeed */
for (tmo = currticks()+5*TICKS_PER_SEC;
diff --git a/gpxe/src/drivers/net/e1000/e1000.h b/gpxe/src/drivers/net/e1000/e1000.h
index 4ae41451..77a09ef1 100644
--- a/gpxe/src/drivers/net/e1000/e1000.h
+++ b/gpxe/src/drivers/net/e1000/e1000.h
@@ -34,7 +34,8 @@
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
-#include <io.h>
+#include <string.h>
+#include <gpxe/io.h>
#include <errno.h>
#include <byteswap.h>
#include <gpxe/pci.h>
diff --git a/gpxe/src/drivers/net/e1000/e1000_osdep.h b/gpxe/src/drivers/net/e1000/e1000_osdep.h
index 7df9b5e9..c2d9eb9c 100644
--- a/gpxe/src/drivers/net/e1000/e1000_osdep.h
+++ b/gpxe/src/drivers/net/e1000/e1000_osdep.h
@@ -37,7 +37,7 @@
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
-#include <io.h>
+#include <gpxe/io.h>
#include <errno.h>
#include <unistd.h>
#include <byteswap.h>
@@ -74,60 +74,60 @@ typedef enum {
#define DEBUGOUT3 DEBUGOUT1
#define DEBUGOUT7 DEBUGOUT1
-#define E1000_WRITE_REG(a, reg, value) ( \
+#define E1000_WRITE_REG(a, reg, value) \
writel((value), ((a)->hw_addr + \
- (((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg))))
+ (((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg)))
-#define E1000_READ_REG(a, reg) ( \
+#define E1000_READ_REG(a, reg) \
readl((a)->hw_addr + \
- (((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg)))
+ (((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg))
-#define E1000_WRITE_REG_ARRAY(a, reg, offset, value) ( \
+#define E1000_WRITE_REG_ARRAY(a, reg, offset, value) \
writel((value), ((a)->hw_addr + \
(((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg) + \
- ((offset) << 2))))
+ ((offset) << 2)))
-#define E1000_READ_REG_ARRAY(a, reg, offset) ( \
+#define E1000_READ_REG_ARRAY(a, reg, offset) \
readl((a)->hw_addr + \
(((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg) + \
- ((offset) << 2)))
+ ((offset) << 2))
#define E1000_READ_REG_ARRAY_DWORD E1000_READ_REG_ARRAY
#define E1000_WRITE_REG_ARRAY_DWORD E1000_WRITE_REG_ARRAY
-#define E1000_WRITE_REG_ARRAY_WORD(a, reg, offset, value) ( \
+#define E1000_WRITE_REG_ARRAY_WORD(a, reg, offset, value) \
writew((value), ((a)->hw_addr + \
(((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg) + \
- ((offset) << 1))))
+ ((offset) << 1)))
-#define E1000_READ_REG_ARRAY_WORD(a, reg, offset) ( \
+#define E1000_READ_REG_ARRAY_WORD(a, reg, offset) \
readw((a)->hw_addr + \
(((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg) + \
- ((offset) << 1)))
+ ((offset) << 1))
-#define E1000_WRITE_REG_ARRAY_BYTE(a, reg, offset, value) ( \
+#define E1000_WRITE_REG_ARRAY_BYTE(a, reg, offset, value) \
writeb((value), ((a)->hw_addr + \
(((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg) + \
- (offset))))
+ (offset)))
-#define E1000_READ_REG_ARRAY_BYTE(a, reg, offset) ( \
+#define E1000_READ_REG_ARRAY_BYTE(a, reg, offset) \
readb((a)->hw_addr + \
(((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg) + \
- (offset)))
+ (offset))
#define E1000_WRITE_FLUSH(a) E1000_READ_REG(a, STATUS)
-#define E1000_WRITE_ICH_FLASH_REG(a, reg, value) ( \
- writel((value), ((a)->flash_address + reg)))
+#define E1000_WRITE_ICH_FLASH_REG(a, reg, value) \
+ writel((value), ((a)->flash_address + reg))
-#define E1000_READ_ICH_FLASH_REG(a, reg) ( \
- readl((a)->flash_address + reg))
+#define E1000_READ_ICH_FLASH_REG(a, reg) \
+ readl((a)->flash_address + reg)
-#define E1000_WRITE_ICH_FLASH_REG16(a, reg, value) ( \
- writew((value), ((a)->flash_address + reg)))
+#define E1000_WRITE_ICH_FLASH_REG16(a, reg, value) \
+ writew((value), ((a)->flash_address + reg))
-#define E1000_READ_ICH_FLASH_REG16(a, reg) ( \
- readw((a)->flash_address + reg))
+#define E1000_READ_ICH_FLASH_REG16(a, reg) \
+ readw((a)->flash_address + reg)
#define msleep(n) mdelay(n)
diff --git a/gpxe/src/drivers/net/eepro100.c b/gpxe/src/drivers/net/eepro100.c
index f746976a..e6e7db49 100644
--- a/gpxe/src/drivers/net/eepro100.c
+++ b/gpxe/src/drivers/net/eepro100.c
@@ -407,7 +407,7 @@ static void eepro100_transmit(struct nic *nic, const char *d, unsigned int t, un
} hdr;
unsigned short status;
int s1, s2;
- tick_t ct;
+ unsigned long ct;
status = inw(ioaddr + SCBStatus);
/* Acknowledge all of the current interrupt sources ASAP. */
@@ -448,7 +448,7 @@ static void eepro100_transmit(struct nic *nic, const char *d, unsigned int t, un
ct = currticks();
/* timeout 10 ms for transmit */
- while (!txfd.status && ct + 10*USECS_IN_MSEC)
+ while (!txfd.status && ct + 10*1000)
/* Wait */;
s2 = inw (ioaddr + SCBStatus);
@@ -608,7 +608,7 @@ static int eepro100_probe ( struct nic *nic, struct pci_device *pci ) {
int read_cmd, ee_size;
int options;
int rx_mode;
- tick_t ct;
+ unsigned long ct;
/* we cache only the first few words of the EEPROM data
be careful not to access beyond this array */
@@ -753,7 +753,7 @@ static int eepro100_probe ( struct nic *nic, struct pci_device *pci ) {
whereami ("started TX thingy (config, iasetup).");
ct = currticks();
- while (!txfd.status && ct + 10*USECS_IN_MSEC < currticks())
+ while (!txfd.status && ct + 10*1000 < currticks())
/* Wait */;
/* Read the status register once to disgard stale data */
diff --git a/gpxe/src/drivers/net/epic100.c b/gpxe/src/drivers/net/epic100.c
index 67b4f0fb..1e36a680 100644
--- a/gpxe/src/drivers/net/epic100.c
+++ b/gpxe/src/drivers/net/epic100.c
@@ -309,7 +309,7 @@ epic100_transmit(struct nic *nic, const char *destaddr, unsigned int type,
unsigned short nstype;
unsigned char *txp;
int entry;
- tick_t ct;
+ unsigned long ct;
/* Calculate the next Tx descriptor entry. */
entry = cur_tx % TX_RING_SIZE;
@@ -352,7 +352,7 @@ epic100_transmit(struct nic *nic, const char *destaddr, unsigned int type,
ct = currticks();
/* timeout 10 ms for transmit */
while ((le32_to_cpu(tx_ring[entry].status) & (TRING_OWN)) &&
- ct + 10*USECS_IN_MSEC < currticks())
+ ct + 10*1000 < currticks())
/* Wait */;
if ((le32_to_cpu(tx_ring[entry].status) & TRING_OWN) != 0)
diff --git a/gpxe/src/drivers/net/etherfabric.c b/gpxe/src/drivers/net/etherfabric.c
index 8a6b1a17..7cd29f27 100644
--- a/gpxe/src/drivers/net/etherfabric.c
+++ b/gpxe/src/drivers/net/etherfabric.c
@@ -15,17 +15,21 @@
*
**************************************************************************
*/
-
-#include "etherboot.h"
-#include "nic.h"
+#include <stdint.h>
+#include <stdlib.h>
+#include <unistd.h>
#include <errno.h>
+#include <assert.h>
+#include <byteswap.h>
+#include <console.h>
#include <gpxe/pci.h>
-#include <gpxe/bitbash.h>
-#include <gpxe/i2c.h>
-#include <gpxe/spi.h>
-#include <gpxe/nvo.h>
-#define dma_addr_t unsigned long
+#include <gpxe/malloc.h>
+#include <gpxe/ethernet.h>
+#include <gpxe/iobuf.h>
+#include <gpxe/netdevice.h>
+#include <gpxe/timer.h>
#include "etherfabric.h"
+#include "etherfabric_nic.h"
/**************************************************************************
*
@@ -34,193 +38,35 @@
**************************************************************************
*/
-#define EFAB_ASSERT(x) \
- do { \
- if ( ! (x) ) { \
- DBG ( "ASSERT(%s) failed at %s line %d [%s]\n", #x, \
- __FILE__, __LINE__, __FUNCTION__ ); \
- } \
- } while (0)
-
-#define EFAB_TRACE(...) DBG ( __VA_ARGS__ )
-
#define EFAB_REGDUMP(...)
+#define EFAB_TRACE(...) DBGP(__VA_ARGS__)
-#define EFAB_LOG(...) printf ( __VA_ARGS__ )
-#define EFAB_ERR(...) printf ( __VA_ARGS__ )
-
-#define FALCON_USE_IO_BAR 1
+// printf() is not allowed within drivers. Use DBG() instead.
+#define EFAB_LOG(...) DBG(__VA_ARGS__)
+#define EFAB_ERR(...) DBG(__VA_ARGS__)
-/*
- * EtherFabric constants
- *
- */
+#define FALCON_USE_IO_BAR 0
-/* PCI Definitions */
-#define EFAB_VENDID_LEVEL5 0x1924
-#define FALCON_P_DEVID 0x0703 /* Temporary PCI ID */
-#define EF1002_DEVID 0xC101
+#define HZ 100
+#define EFAB_BYTE 1
/**************************************************************************
*
- * Data structures
+ * Hardware data structures and sizing
*
**************************************************************************
*/
+extern int __invalid_queue_size;
+#define FQS(_prefix, _x) \
+ ( ( (_x) == 512 ) ? _prefix ## _SIZE_512 : \
+ ( ( (_x) == 1024 ) ? _prefix ## _SIZE_1K : \
+ ( ( (_x) == 2048 ) ? _prefix ## _SIZE_2K : \
+ ( ( (_x) == 4096) ? _prefix ## _SIZE_4K : \
+ __invalid_queue_size ) ) ) )
-/*
- * Buffers used for TX, RX and event queue
- *
- */
-#define EFAB_BUF_ALIGN 4096
-#define EFAB_DATA_BUF_SIZE 2048
-#define EFAB_RX_BUFS 16
-#define EFAB_RXD_SIZE 512
-#define EFAB_TXD_SIZE 512
-#define EFAB_EVQ_SIZE 512
-struct efab_buffers {
- uint8_t eventq[4096];
- uint8_t rxd[4096];
- uint8_t txd[4096];
- uint8_t tx_buf[EFAB_DATA_BUF_SIZE];
- uint8_t rx_buf[EFAB_RX_BUFS][EFAB_DATA_BUF_SIZE];
- uint8_t padding[EFAB_BUF_ALIGN-1];
-};
-static struct efab_buffers efab_buffers;
-
-/** An RX buffer */
-struct efab_rx_buf {
- uint8_t *addr;
- unsigned int len;
- int id;
-};
-
-/** A TX buffer */
-struct efab_tx_buf {
- uint8_t *addr;
- unsigned int len;
- int id;
-};
-
-/** Etherfabric event type */
-enum efab_event_type {
- EFAB_EV_NONE = 0,
- EFAB_EV_TX,
- EFAB_EV_RX,
-};
-
-/** Etherfabric event */
-struct efab_event {
- /** Event type */
- enum efab_event_type type;
- /** RX buffer ID */
- int rx_id;
- /** RX length */
- unsigned int rx_len;
- /** Packet should be dropped */
- int drop;
-};
-
-/*
- * Etherfabric abstraction layer
- *
- */
-struct efab_nic;
-struct efab_operations {
- void ( * get_membase ) ( struct efab_nic *efab );
- int ( * reset ) ( struct efab_nic *efab );
- int ( * init_nic ) ( struct efab_nic *efab );
- int ( * read_eeprom ) ( struct efab_nic *efab );
- void ( * build_rx_desc ) ( struct efab_nic *efab,
- struct efab_rx_buf *rx_buf );
- void ( * notify_rx_desc ) ( struct efab_nic *efab );
- void ( * build_tx_desc ) ( struct efab_nic *efab,
- struct efab_tx_buf *tx_buf );
- void ( * notify_tx_desc ) ( struct efab_nic *efab );
- int ( * fetch_event ) ( struct efab_nic *efab,
- struct efab_event *event );
- void ( * mask_irq ) ( struct efab_nic *efab, int enabled );
- void ( * generate_irq ) ( struct efab_nic *efab );
- void ( * mdio_write ) ( struct efab_nic *efab, int location,
- int value );
- int ( * mdio_read ) ( struct efab_nic *efab, int location );
-};
-
-struct efab_mac_operations {
- void ( * mac_writel ) ( struct efab_nic *efab, efab_dword_t *value,
- unsigned int mac_reg );
- void ( * mac_readl ) ( struct efab_nic *efab, efab_dword_t *value,
- unsigned int mac_reg );
- int ( * init ) ( struct efab_nic *efab );
- int ( * reset ) ( struct efab_nic *efab );
-};
-
-/*
- * Driver private data structure
- *
- */
-struct efab_nic {
-
- /** PCI device */
- struct pci_device *pci;
-
- /** Operations table */
- struct efab_operations *op;
-
- /** MAC operations table */
- struct efab_mac_operations *mac_op;
- /** Memory base */
- void *membase;
-
- /** I/O base */
- unsigned int iobase;
-
- /** Buffers */
- uint8_t *eventq; /* Falcon only */
- uint8_t *txd; /* Falcon only */
- uint8_t *rxd; /* Falcon only */
- struct efab_tx_buf tx_buf;
- struct efab_rx_buf rx_bufs[EFAB_RX_BUFS];
-
- /** Buffer pointers */
- unsigned int eventq_read_ptr; /* Falcon only */
- unsigned int tx_write_ptr;
- unsigned int rx_write_ptr;
-
- /** Port 0/1 on the NIC */
- int port;
-
- /** MAC address */
- uint8_t mac_addr[ETH_ALEN];
- /** GMII link options */
- unsigned int link_options;
- /** Link status */
- int link_up;
-
- /* Nic type fields */
- int has_flash : 1;
- int has_eeprom : 1;
- int is_10g : 1;
- int is_dual : 1;
- int is_asic : 1;
-
- /** INT_REG_KER for Falcon */
- efab_oword_t int_ker __attribute__ (( aligned ( 16 ) ));
-
- /** I2C access */
- struct i2c_bit_basher ef1002_i2c;
- unsigned long ef1002_i2c_outputs;
- struct i2c_device ef1002_eeprom;
-
- /** SPI access */
- struct spi_bus spi;
- struct spi_device falcon_flash;
- struct spi_device falcon_eeprom;
-
- /** Non-volatile options */
- struct nvo_block nvo;
-};
+#define EFAB_MAX_FRAME_LEN(mtu) \
+ ( ( ( ( mtu ) + 4/* FCS */ ) + 7 ) & ~7 )
/**************************************************************************
*
@@ -229,6 +75,10 @@ struct efab_nic {
**************************************************************************
*/
+static void falcon_mdio_write (struct efab_nic *efab, int device,
+ int location, int value );
+static int falcon_mdio_read ( struct efab_nic *efab, int device, int location );
+
/* GMII registers */
#define MII_BMSR 0x01 /* Basic mode status register */
#define MII_ADVERTISE 0x04 /* Advertisement control register */
@@ -257,7 +107,8 @@ struct efab_nic {
#define LPA_100 (LPA_100FULL | LPA_100HALF | LPA_100BASE4)
#define LPA_1000 ( LPA_1000FULL | LPA_1000HALF )
#define LPA_10000 ( LPA_10000FULL | LPA_10000HALF )
-#define LPA_DUPLEX ( LPA_10FULL | LPA_100FULL | LPA_1000FULL )
+#define LPA_DUPLEX ( LPA_10FULL | LPA_100FULL | LPA_1000FULL | \
+ LPA_10000FULL )
/* Mask of bits not associated with speed or duplexity. */
#define LPA_OTHER ~( LPA_10FULL | LPA_10HALF | LPA_100FULL | \
@@ -270,13 +121,15 @@ struct efab_nic {
* Retrieve GMII autonegotiation advertised abilities
*
*/
-static unsigned int gmii_autoneg_advertised ( struct efab_nic *efab ) {
+static unsigned int
+gmii_autoneg_advertised ( struct efab_nic *efab )
+{
unsigned int mii_advertise;
unsigned int gmii_advertise;
-
+
/* Extended bits are in bits 8 and 9 of GMII_GTCR */
- mii_advertise = efab->op->mdio_read ( efab, MII_ADVERTISE );
- gmii_advertise = ( ( efab->op->mdio_read ( efab, GMII_GTCR ) >> 8 )
+ mii_advertise = falcon_mdio_read ( efab, 0, MII_ADVERTISE );
+ gmii_advertise = ( ( falcon_mdio_read ( efab, 0, GMII_GTCR ) >> 8 )
& 0x03 );
return ( ( gmii_advertise << 16 ) | mii_advertise );
}
@@ -285,13 +138,15 @@ static unsigned int gmii_autoneg_advertised ( struct efab_nic *efab ) {
* Retrieve GMII autonegotiation link partner abilities
*
*/
-static unsigned int gmii_autoneg_lpa ( struct efab_nic *efab ) {
+static unsigned int
+gmii_autoneg_lpa ( struct efab_nic *efab )
+{
unsigned int mii_lpa;
unsigned int gmii_lpa;
-
+
/* Extended bits are in bits 10 and 11 of GMII_GTSR */
- mii_lpa = efab->op->mdio_read ( efab, MII_LPA );
- gmii_lpa = ( efab->op->mdio_read ( efab, GMII_GTSR ) >> 10 ) & 0x03;
+ mii_lpa = falcon_mdio_read ( efab, 0, MII_LPA );
+ gmii_lpa = ( falcon_mdio_read ( efab, 0, GMII_GTSR ) >> 10 ) & 0x03;
return ( ( gmii_lpa << 16 ) | mii_lpa );
}
@@ -299,7 +154,9 @@ static unsigned int gmii_autoneg_lpa ( struct efab_nic *efab ) {
* Calculate GMII autonegotiated link technology
*
*/
-static unsigned int gmii_nway_result ( unsigned int negotiated ) {
+static unsigned int
+gmii_nway_result ( unsigned int negotiated )
+{
unsigned int other_bits;
/* Mask out the speed and duplexity bits */
@@ -324,1167 +181,244 @@ static unsigned int gmii_nway_result ( unsigned int negotiated ) {
* Check GMII PHY link status
*
*/
-static int gmii_link_ok ( struct efab_nic *efab ) {
+static int
+gmii_link_ok ( struct efab_nic *efab )
+{
int status;
int phy_status;
-
+
/* BMSR is latching - it returns "link down" if the link has
* been down at any point since the last read. To get a
* real-time status, we therefore read the register twice and
* use the result of the second read.
*/
- efab->op->mdio_read ( efab, MII_BMSR );
- status = efab->op->mdio_read ( efab, MII_BMSR );
+ (void) falcon_mdio_read ( efab, 0, MII_BMSR );
+ status = falcon_mdio_read ( efab, 0, MII_BMSR );
/* Read the PHY-specific Status Register. This is
* non-latching, so we need do only a single read.
*/
- phy_status = efab->op->mdio_read ( efab, GMII_PSSR );
+ phy_status = falcon_mdio_read ( efab, 0, GMII_PSSR );
return ( ( status & BMSR_LSTATUS ) && ( phy_status & PSSR_LSTATUS ) );
}
/**************************************************************************
*
- * Alaska PHY
+ * MDIO routines
*
**************************************************************************
*/
-/**
- * Initialise Alaska PHY
- *
- */
-static void alaska_init ( struct efab_nic *efab ) {
- unsigned int advertised, lpa;
-
- /* Read link up status */
- efab->link_up = gmii_link_ok ( efab );
-
- if ( ! efab->link_up )
- return;
-
- /* Determine link options from PHY. */
- advertised = gmii_autoneg_advertised ( efab );
- lpa = gmii_autoneg_lpa ( efab );
- efab->link_options = gmii_nway_result ( advertised & lpa );
-
- /* print out the link speed */
- EFAB_LOG ( "%dMbps %s-duplex (%04x,%04x)\n",
- ( efab->link_options & LPA_10000 ? 1000 :
- ( efab->link_options & LPA_1000 ? 1000 :
- ( efab->link_options & LPA_100 ? 100 : 10 ) ) ),
- ( efab->link_options & LPA_DUPLEX ? "full" : "half" ),
- advertised, lpa );
-}
-
-
-/**************************************************************************
- *
- * Mentor MAC
- *
- **************************************************************************
- */
-
-/* GMAC configuration register 1 */
-#define GM_CFG1_REG_MAC 0x00
-#define GM_SW_RST_LBN 31
-#define GM_SW_RST_WIDTH 1
-#define GM_RX_FC_EN_LBN 5
-#define GM_RX_FC_EN_WIDTH 1
-#define GM_TX_FC_EN_LBN 4
-#define GM_TX_FC_EN_WIDTH 1
-#define GM_RX_EN_LBN 2
-#define GM_RX_EN_WIDTH 1
-#define GM_TX_EN_LBN 0
-#define GM_TX_EN_WIDTH 1
-
-/* GMAC configuration register 2 */
-#define GM_CFG2_REG_MAC 0x01
-#define GM_PAMBL_LEN_LBN 12
-#define GM_PAMBL_LEN_WIDTH 4
-#define GM_IF_MODE_LBN 8
-#define GM_IF_MODE_WIDTH 2
-#define GM_PAD_CRC_EN_LBN 2
-#define GM_PAD_CRC_EN_WIDTH 1
-#define GM_FD_LBN 0
-#define GM_FD_WIDTH 1
-
-/* GMAC maximum frame length register */
-#define GM_MAX_FLEN_REG_MAC 0x04
-#define GM_MAX_FLEN_LBN 0
-#define GM_MAX_FLEN_WIDTH 16
-
-/* GMAC MII management configuration register */
-#define GM_MII_MGMT_CFG_REG_MAC 0x08
-#define GM_MGMT_CLK_SEL_LBN 0
-#define GM_MGMT_CLK_SEL_WIDTH 3
-
-/* GMAC MII management command register */
-#define GM_MII_MGMT_CMD_REG_MAC 0x09
-#define GM_MGMT_SCAN_CYC_LBN 1
-#define GM_MGMT_SCAN_CYC_WIDTH 1
-#define GM_MGMT_RD_CYC_LBN 0
-#define GM_MGMT_RD_CYC_WIDTH 1
-
-/* GMAC MII management address register */
-#define GM_MII_MGMT_ADR_REG_MAC 0x0a
-#define GM_MGMT_PHY_ADDR_LBN 8
-#define GM_MGMT_PHY_ADDR_WIDTH 5
-#define GM_MGMT_REG_ADDR_LBN 0
-#define GM_MGMT_REG_ADDR_WIDTH 5
-
-/* GMAC MII management control register */
-#define GM_MII_MGMT_CTL_REG_MAC 0x0b
-#define GM_MGMT_CTL_LBN 0
-#define GM_MGMT_CTL_WIDTH 16
-
-/* GMAC MII management status register */
-#define GM_MII_MGMT_STAT_REG_MAC 0x0c
-#define GM_MGMT_STAT_LBN 0
-#define GM_MGMT_STAT_WIDTH 16
-
-/* GMAC MII management indicators register */
-#define GM_MII_MGMT_IND_REG_MAC 0x0d
-#define GM_MGMT_BUSY_LBN 0
-#define GM_MGMT_BUSY_WIDTH 1
-
-/* GMAC station address register 1 */
-#define GM_ADR1_REG_MAC 0x10
-#define GM_HWADDR_5_LBN 24
-#define GM_HWADDR_5_WIDTH 8
-#define GM_HWADDR_4_LBN 16
-#define GM_HWADDR_4_WIDTH 8
-#define GM_HWADDR_3_LBN 8
-#define GM_HWADDR_3_WIDTH 8
-#define GM_HWADDR_2_LBN 0
-#define GM_HWADDR_2_WIDTH 8
-
-/* GMAC station address register 2 */
-#define GM_ADR2_REG_MAC 0x11
-#define GM_HWADDR_1_LBN 24
-#define GM_HWADDR_1_WIDTH 8
-#define GM_HWADDR_0_LBN 16
-#define GM_HWADDR_0_WIDTH 8
-
-/* GMAC FIFO configuration register 0 */
-#define GMF_CFG0_REG_MAC 0x12
-#define GMF_FTFENREQ_LBN 12
-#define GMF_FTFENREQ_WIDTH 1
-#define GMF_STFENREQ_LBN 11
-#define GMF_STFENREQ_WIDTH 1
-#define GMF_FRFENREQ_LBN 10
-#define GMF_FRFENREQ_WIDTH 1
-#define GMF_SRFENREQ_LBN 9
-#define GMF_SRFENREQ_WIDTH 1
-#define GMF_WTMENREQ_LBN 8
-#define GMF_WTMENREQ_WIDTH 1
-
-/* GMAC FIFO configuration register 1 */
-#define GMF_CFG1_REG_MAC 0x13
-#define GMF_CFGFRTH_LBN 16
-#define GMF_CFGFRTH_WIDTH 5
-#define GMF_CFGXOFFRTX_LBN 0
-#define GMF_CFGXOFFRTX_WIDTH 16
-
-/* GMAC FIFO configuration register 2 */
-#define GMF_CFG2_REG_MAC 0x14
-#define GMF_CFGHWM_LBN 16
-#define GMF_CFGHWM_WIDTH 6
-#define GMF_CFGLWM_LBN 0
-#define GMF_CFGLWM_WIDTH 6
-
-/* GMAC FIFO configuration register 3 */
-#define GMF_CFG3_REG_MAC 0x15
-#define GMF_CFGHWMFT_LBN 16
-#define GMF_CFGHWMFT_WIDTH 6
-#define GMF_CFGFTTH_LBN 0
-#define GMF_CFGFTTH_WIDTH 6
-
-/* GMAC FIFO configuration register 4 */
-#define GMF_CFG4_REG_MAC 0x16
-#define GMF_HSTFLTRFRM_PAUSE_LBN 12
-#define GMF_HSTFLTRFRM_PAUSE_WIDTH 12
-
-/* GMAC FIFO configuration register 5 */
-#define GMF_CFG5_REG_MAC 0x17
-#define GMF_CFGHDPLX_LBN 22
-#define GMF_CFGHDPLX_WIDTH 1
-#define GMF_CFGBYTMODE_LBN 19
-#define GMF_CFGBYTMODE_WIDTH 1
-#define GMF_HSTDRPLT64_LBN 18
-#define GMF_HSTDRPLT64_WIDTH 1
-#define GMF_HSTFLTRFRMDC_PAUSE_LBN 12
-#define GMF_HSTFLTRFRMDC_PAUSE_WIDTH 1
-
-struct efab_mentormac_parameters {
- int gmf_cfgfrth;
- int gmf_cfgftth;
- int gmf_cfghwmft;
- int gmf_cfghwm;
- int gmf_cfglwm;
-};
-
-/**
- * Reset Mentor MAC
- *
- */
-static void mentormac_reset ( struct efab_nic *efab ) {
- efab_dword_t reg;
- int save_port;
-
- /* Take into reset */
- EFAB_POPULATE_DWORD_1 ( reg, GM_SW_RST, 1 );
- efab->mac_op->mac_writel ( efab, &reg, GM_CFG1_REG_MAC );
- udelay ( 1000 );
-
- /* Take out of reset */
- EFAB_POPULATE_DWORD_1 ( reg, GM_SW_RST, 0 );
- efab->mac_op->mac_writel ( efab, &reg, GM_CFG1_REG_MAC );
- udelay ( 1000 );
-
- /* Mentor MAC connects both PHYs to MAC 0 */
- save_port = efab->port;
- efab->port = 0;
- /* Configure GMII interface so PHY is accessible. Note that
- * GMII interface is connected only to port 0, and that on
- * Falcon this is a no-op.
- */
- EFAB_POPULATE_DWORD_1 ( reg, GM_MGMT_CLK_SEL, 0x4 );
- efab->mac_op->mac_writel ( efab, &reg, GM_MII_MGMT_CFG_REG_MAC );
- udelay ( 10 );
- efab->port = save_port;
-}
-
-/**
- * Initialise Mentor MAC
- *
- */
-static void mentormac_init ( struct efab_nic *efab,
- struct efab_mentormac_parameters *params ) {
- int pause, if_mode, full_duplex, bytemode, half_duplex;
- efab_dword_t reg;
-
- /* Configuration register 1 */
- pause = ( efab->link_options & LPA_PAUSE ) ? 1 : 0;
- if ( ! ( efab->link_options & LPA_DUPLEX ) ) {
- /* Half-duplex operation requires TX flow control */
- pause = 1;
+/* Numbering of the MDIO Manageable Devices (MMDs) */
+/* Physical Medium Attachment/ Physical Medium Dependent sublayer */
+#define MDIO_MMD_PMAPMD (1)
+/* WAN Interface Sublayer */
+#define MDIO_MMD_WIS (2)
+/* Physical Coding Sublayer */
+#define MDIO_MMD_PCS (3)
+/* PHY Extender Sublayer */
+#define MDIO_MMD_PHYXS (4)
+/* Extender Sublayer */
+#define MDIO_MMD_DTEXS (5)
+/* Transmission convergence */
+#define MDIO_MMD_TC (6)
+/* Auto negotiation */
+#define MDIO_MMD_AN (7)
+
+/* Generic register locations */
+#define MDIO_MMDREG_CTRL1 (0)
+#define MDIO_MMDREG_STAT1 (1)
+#define MDIO_MMDREG_DEVS0 (5)
+#define MDIO_MMDREG_STAT2 (8)
+
+/* Bits in MMDREG_CTRL1 */
+/* Reset */
+#define MDIO_MMDREG_CTRL1_RESET_LBN (15)
+#define MDIO_MMDREG_CTRL1_RESET_WIDTH (1)
+
+/* Bits in MMDREG_STAT1 */
+#define MDIO_MMDREG_STAT1_FAULT_LBN (7)
+#define MDIO_MMDREG_STAT1_FAULT_WIDTH (1)
+
+/* Link state */
+#define MDIO_MMDREG_STAT1_LINK_LBN (2)
+#define MDIO_MMDREG_STAT1_LINK_WIDTH (1)
+
+/* Bits in MMDREG_DEVS0. */
+#define DEV_PRESENT_BIT(_b) (1 << _b)
+
+#define MDIO_MMDREG_DEVS0_DTEXS DEV_PRESENT_BIT(MDIO_MMD_DTEXS)
+#define MDIO_MMDREG_DEVS0_PHYXS DEV_PRESENT_BIT(MDIO_MMD_PHYXS)
+#define MDIO_MMDREG_DEVS0_PCS DEV_PRESENT_BIT(MDIO_MMD_PCS)
+#define MDIO_MMDREG_DEVS0_WIS DEV_PRESENT_BIT(MDIO_MMD_WIS)
+#define MDIO_MMDREG_DEVS0_PMAPMD DEV_PRESENT_BIT(MDIO_MMD_PMAPMD)
+
+#define MDIO_MMDREG_DEVS0_AN DEV_PRESENT_BIT(MDIO_MMD_AN)
+
+/* Bits in MMDREG_STAT2 */
+#define MDIO_MMDREG_STAT2_PRESENT_VAL (2)
+#define MDIO_MMDREG_STAT2_PRESENT_LBN (14)
+#define MDIO_MMDREG_STAT2_PRESENT_WIDTH (2)
+
+/* PHY XGXS lane state */
+#define MDIO_PHYXS_LANE_STATE (0x18)
+#define MDIO_PHYXS_LANE_ALIGNED_LBN (12)
+#define MDIO_PHYXS_LANE_SYNC0_LBN (0)
+#define MDIO_PHYXS_LANE_SYNC1_LBN (1)
+#define MDIO_PHYXS_LANE_SYNC2_LBN (2)
+#define MDIO_PHYXS_LANE_SYNC3_LBN (3)
+
+/* This ought to be ridiculous overkill. We expect it to fail rarely */
+#define MDIO45_RESET_TRIES 100
+#define MDIO45_RESET_SPINTIME 10
+
+static int
+mdio_clause45_wait_reset_mmds ( struct efab_nic* efab )
+{
+ int tries = MDIO45_RESET_TRIES;
+ int in_reset;
+
+ while(tries) {
+ int mask = efab->phy_op->mmds;
+ int mmd = 0;
+ in_reset = 0;
+ while(mask) {
+ if (mask & 1) {
+ int stat = falcon_mdio_read ( efab, mmd,
+ MDIO_MMDREG_CTRL1 );
+ if (stat < 0) {
+ EFAB_ERR("Failed to read status of MMD %d\n",
+ mmd );
+ in_reset = 1;
+ break;
+ }
+ if (stat & (1 << MDIO_MMDREG_CTRL1_RESET_LBN))
+ in_reset |= (1 << mmd);
+ }
+ mask = mask >> 1;
+ mmd++;
+ }
+ if (!in_reset)
+ break;
+ tries--;
+ mdelay ( MDIO45_RESET_SPINTIME );
}
- EFAB_POPULATE_DWORD_4 ( reg,
- GM_TX_EN, 1,
- GM_TX_FC_EN, pause,
- GM_RX_EN, 1,
- GM_RX_FC_EN, 1 );
- efab->mac_op->mac_writel ( efab, &reg, GM_CFG1_REG_MAC );
- udelay ( 10 );
-
- /* Configuration register 2 */
- if_mode = ( efab->link_options & LPA_1000 ) ? 2 : 1;
- full_duplex = ( efab->link_options & LPA_DUPLEX ) ? 1 : 0;
- EFAB_POPULATE_DWORD_4 ( reg,
- GM_IF_MODE, if_mode,
- GM_PAD_CRC_EN, 1,
- GM_FD, full_duplex,
- GM_PAMBL_LEN, 0x7 /* ? */ );
- efab->mac_op->mac_writel ( efab, &reg, GM_CFG2_REG_MAC );
- udelay ( 10 );
-
- /* Max frame len register */
- EFAB_POPULATE_DWORD_1 ( reg, GM_MAX_FLEN, ETH_FRAME_LEN + 4 /* FCS */);
- efab->mac_op->mac_writel ( efab, &reg, GM_MAX_FLEN_REG_MAC );
- udelay ( 10 );
-
- /* FIFO configuration register 0 */
- EFAB_POPULATE_DWORD_5 ( reg,
- GMF_FTFENREQ, 1,
- GMF_STFENREQ, 1,
- GMF_FRFENREQ, 1,
- GMF_SRFENREQ, 1,
- GMF_WTMENREQ, 1 );
- efab->mac_op->mac_writel ( efab, &reg, GMF_CFG0_REG_MAC );
- udelay ( 10 );
-
- /* FIFO configuration register 1 */
- EFAB_POPULATE_DWORD_2 ( reg,
- GMF_CFGFRTH, params->gmf_cfgfrth,
- GMF_CFGXOFFRTX, 0xffff );
- efab->mac_op->mac_writel ( efab, &reg, GMF_CFG1_REG_MAC );
- udelay ( 10 );
-
- /* FIFO configuration register 2 */
- EFAB_POPULATE_DWORD_2 ( reg,
- GMF_CFGHWM, params->gmf_cfghwm,
- GMF_CFGLWM, params->gmf_cfglwm );
- efab->mac_op->mac_writel ( efab, &reg, GMF_CFG2_REG_MAC );
- udelay ( 10 );
-
- /* FIFO configuration register 3 */
- EFAB_POPULATE_DWORD_2 ( reg,
- GMF_CFGHWMFT, params->gmf_cfghwmft,
- GMF_CFGFTTH, params->gmf_cfgftth );
- efab->mac_op->mac_writel ( efab, &reg, GMF_CFG3_REG_MAC );
- udelay ( 10 );
-
- /* FIFO configuration register 4 */
- EFAB_POPULATE_DWORD_1 ( reg, GMF_HSTFLTRFRM_PAUSE, 1 );
- efab->mac_op->mac_writel ( efab, &reg, GMF_CFG4_REG_MAC );
- udelay ( 10 );
-
- /* FIFO configuration register 5 */
- bytemode = ( efab->link_options & LPA_1000 ) ? 1 : 0;
- half_duplex = ( efab->link_options & LPA_DUPLEX ) ? 0 : 1;
- efab->mac_op->mac_readl ( efab, &reg, GMF_CFG5_REG_MAC );
- EFAB_SET_DWORD_FIELD ( reg, GMF_CFGBYTMODE, bytemode );
- EFAB_SET_DWORD_FIELD ( reg, GMF_CFGHDPLX, half_duplex );
- EFAB_SET_DWORD_FIELD ( reg, GMF_HSTDRPLT64, half_duplex );
- EFAB_SET_DWORD_FIELD ( reg, GMF_HSTFLTRFRMDC_PAUSE, 0 );
- efab->mac_op->mac_writel ( efab, &reg, GMF_CFG5_REG_MAC );
- udelay ( 10 );
-
- /* MAC address */
- EFAB_POPULATE_DWORD_4 ( reg,
- GM_HWADDR_5, efab->mac_addr[5],
- GM_HWADDR_4, efab->mac_addr[4],
- GM_HWADDR_3, efab->mac_addr[3],
- GM_HWADDR_2, efab->mac_addr[2] );
- efab->mac_op->mac_writel ( efab, &reg, GM_ADR1_REG_MAC );
- udelay ( 10 );
- EFAB_POPULATE_DWORD_2 ( reg,
- GM_HWADDR_1, efab->mac_addr[1],
- GM_HWADDR_0, efab->mac_addr[0] );
- efab->mac_op->mac_writel ( efab, &reg, GM_ADR2_REG_MAC );
- udelay ( 10 );
-}
-
-/**
- * Wait for GMII access to complete
- *
- */
-static int mentormac_gmii_wait ( struct efab_nic *efab ) {
- int count;
- efab_dword_t indicator;
-
- for ( count = 0 ; count < 1000 ; count++ ) {
- udelay ( 10 );
- efab->mac_op->mac_readl ( efab, &indicator,
- GM_MII_MGMT_IND_REG_MAC );
- if ( EFAB_DWORD_FIELD ( indicator, GM_MGMT_BUSY ) == 0 )
- return 1;
+ if (in_reset != 0) {
+ EFAB_ERR("Not all MMDs came out of reset in time. MMDs "
+ "still in reset: %x\n", in_reset);
+ return -ETIMEDOUT;
}
- EFAB_ERR ( "Timed out waiting for GMII\n" );
return 0;
}
-/**
- * Write a GMII register
- *
- */
-static void mentormac_mdio_write ( struct efab_nic *efab, int phy_id,
- int location, int value ) {
- efab_dword_t reg;
- int save_port;
-
- EFAB_TRACE ( "Writing GMII %d register %02x with %04x\n", phy_id,
- location, value );
-
- /* Mentor MAC connects both PHYs to MAC 0 */
- save_port = efab->port;
- efab->port = 0;
-
- /* Check MII not currently being accessed */
- if ( ! mentormac_gmii_wait ( efab ) )
- goto out;
-
- /* Write the address register */
- EFAB_POPULATE_DWORD_2 ( reg,
- GM_MGMT_PHY_ADDR, phy_id,
- GM_MGMT_REG_ADDR, location );
- efab->mac_op->mac_writel ( efab, &reg, GM_MII_MGMT_ADR_REG_MAC );
- udelay ( 10 );
-
- /* Write data */
- EFAB_POPULATE_DWORD_1 ( reg, GM_MGMT_CTL, value );
- efab->mac_op->mac_writel ( efab, &reg, GM_MII_MGMT_CTL_REG_MAC );
-
- /* Wait for data to be written */
- mentormac_gmii_wait ( efab );
-
- out:
- /* Restore efab->port */
- efab->port = save_port;
-}
-
-/**
- * Read a GMII register
- *
- */
-static int mentormac_mdio_read ( struct efab_nic *efab, int phy_id,
- int location ) {
- efab_dword_t reg;
- int value = 0xffff;
- int save_port;
-
- /* Mentor MAC connects both PHYs to MAC 0 */
- save_port = efab->port;
- efab->port = 0;
-
- /* Check MII not currently being accessed */
- if ( ! mentormac_gmii_wait ( efab ) )
- goto out;
-
- /* Write the address register */
- EFAB_POPULATE_DWORD_2 ( reg,
- GM_MGMT_PHY_ADDR, phy_id,
- GM_MGMT_REG_ADDR, location );
- efab->mac_op->mac_writel ( efab, &reg, GM_MII_MGMT_ADR_REG_MAC );
- udelay ( 10 );
-
- /* Request data to be read */
- EFAB_POPULATE_DWORD_1 ( reg, GM_MGMT_RD_CYC, 1 );
- efab->mac_op->mac_writel ( efab, &reg, GM_MII_MGMT_CMD_REG_MAC );
-
- /* Wait for data to be become available */
- if ( mentormac_gmii_wait ( efab ) ) {
- /* Read data */
- efab->mac_op->mac_readl ( efab, &reg, GM_MII_MGMT_STAT_REG_MAC );
- value = EFAB_DWORD_FIELD ( reg, GM_MGMT_STAT );
- EFAB_TRACE ( "Read from GMII %d register %02x, got %04x\n",
- phy_id, location, value );
- }
-
- /* Signal completion */
- EFAB_ZERO_DWORD ( reg );
- efab->mac_op->mac_writel ( efab, &reg, GM_MII_MGMT_CMD_REG_MAC );
- udelay ( 10 );
-
- out:
- /* Restore efab->port */
- efab->port = save_port;
-
- return value;
-}
-
-/**************************************************************************
- *
- * EF1002 routines
- *
- **************************************************************************
- */
-
-/** Control and General Status */
-#define EF1_CTR_GEN_STATUS0_REG 0x0
-#define EF1_MASTER_EVENTS_LBN 12
-#define EF1_MASTER_EVENTS_WIDTH 1
-#define EF1_TX_ENGINE_EN_LBN 19
-#define EF1_TX_ENGINE_EN_WIDTH 1
-#define EF1_RX_ENGINE_EN_LBN 18
-#define EF1_RX_ENGINE_EN_WIDTH 1
-#define EF1_TURBO2_LBN 17
-#define EF1_TURBO2_WIDTH 1
-#define EF1_TURBO1_LBN 16
-#define EF1_TURBO1_WIDTH 1
-#define EF1_TURBO3_LBN 14
-#define EF1_TURBO3_WIDTH 1
-#define EF1_LB_RESET_LBN 3
-#define EF1_LB_RESET_WIDTH 1
-#define EF1_MAC_RESET_LBN 2
-#define EF1_MAC_RESET_WIDTH 1
-#define EF1_CAM_ENABLE_LBN 1
-#define EF1_CAM_ENABLE_WIDTH 1
-
-/** IRQ sources */
-#define EF1_IRQ_SRC_REG 0x0008
-
-/** IRQ mask */
-#define EF1_IRQ_MASK_REG 0x000c
-#define EF1_IRQ_PHY1_LBN 11
-#define EF1_IRQ_PHY1_WIDTH 1
-#define EF1_IRQ_PHY0_LBN 10
-#define EF1_IRQ_PHY0_WIDTH 1
-#define EF1_IRQ_SERR_LBN 7
-#define EF1_IRQ_SERR_WIDTH 1
-#define EF1_IRQ_EVQ_LBN 3
-#define EF1_IRQ_EVQ_WIDTH 1
-
-/** Event generation */
-#define EF1_EVT3_REG 0x38
-
-/** EEPROMaccess */
-#define EF1_EEPROM_REG 0x40
-#define EF1_EEPROM_SDA_LBN 31
-#define EF1_EEPROM_SDA_WIDTH 1
-#define EF1_EEPROM_SCL_LBN 30
-#define EF1_EEPROM_SCL_WIDTH 1
-#define EF1_JTAG_DISCONNECT_LBN 17
-#define EF1_JTAG_DISCONNECT_WIDTH 1
-#define EF1_EEPROM_LBN 0
-#define EF1_EEPROM_WIDTH 32
-
-/** Control register 2 */
-#define EF1_CTL2_REG 0x4c
-#define EF1_PLL_TRAP_LBN 31
-#define EF1_PLL_TRAP_WIDTH 1
-#define EF1_MEM_MAP_4MB_LBN 11
-#define EF1_MEM_MAP_4MB_WIDTH 1
-#define EF1_EV_INTR_CLR_WRITE_LBN 6
-#define EF1_EV_INTR_CLR_WRITE_WIDTH 1
-#define EF1_BURST_MERGE_LBN 5
-#define EF1_BURST_MERGE_WIDTH 1
-#define EF1_CLEAR_NULL_PAD_LBN 4
-#define EF1_CLEAR_NULL_PAD_WIDTH 1
-#define EF1_SW_RESET_LBN 2
-#define EF1_SW_RESET_WIDTH 1
-#define EF1_INTR_AFTER_EVENT_LBN 1
-#define EF1_INTR_AFTER_EVENT_WIDTH 1
-
-/** Event FIFO */
-#define EF1_EVENT_FIFO_REG 0x50
-
-/** Event FIFO count */
-#define EF1_EVENT_FIFO_COUNT_REG 0x5c
-#define EF1_EV_COUNT_LBN 0
-#define EF1_EV_COUNT_WIDTH 16
-
-/** TX DMA control and status */
-#define EF1_DMA_TX_CSR_REG 0x80
-#define EF1_DMA_TX_CSR_CHAIN_EN_LBN 8
-#define EF1_DMA_TX_CSR_CHAIN_EN_WIDTH 1
-#define EF1_DMA_TX_CSR_ENABLE_LBN 4
-#define EF1_DMA_TX_CSR_ENABLE_WIDTH 1
-#define EF1_DMA_TX_CSR_INT_EN_LBN 0
-#define EF1_DMA_TX_CSR_INT_EN_WIDTH 1
-
-/** RX DMA control and status */
-#define EF1_DMA_RX_CSR_REG 0xa0
-#define EF1_DMA_RX_ABOVE_1GB_EN_LBN 6
-#define EF1_DMA_RX_ABOVE_1GB_EN_WIDTH 1
-#define EF1_DMA_RX_BELOW_1MB_EN_LBN 5
-#define EF1_DMA_RX_BELOW_1MB_EN_WIDTH 1
-#define EF1_DMA_RX_CSR_ENABLE_LBN 0
-#define EF1_DMA_RX_CSR_ENABLE_WIDTH 1
-
-/** Level 5 watermark register (in MAC space) */
-#define EF1_GMF_L5WM_REG_MAC 0x20
-#define EF1_L5WM_LBN 0
-#define EF1_L5WM_WIDTH 32
-
-/** MAC clock */
-#define EF1_GM_MAC_CLK_REG 0x112000
-#define EF1_GM_PORT0_MAC_CLK_LBN 0
-#define EF1_GM_PORT0_MAC_CLK_WIDTH 1
-#define EF1_GM_PORT1_MAC_CLK_LBN 1
-#define EF1_GM_PORT1_MAC_CLK_WIDTH 1
-
-/** TX descriptor FIFO */
-#define EF1_TX_DESC_FIFO 0x141000
-#define EF1_TX_KER_EVQ_LBN 80
-#define EF1_TX_KER_EVQ_WIDTH 12
-#define EF1_TX_KER_IDX_LBN 64
-#define EF1_TX_KER_IDX_WIDTH 16
-#define EF1_TX_KER_MODE_LBN 63
-#define EF1_TX_KER_MODE_WIDTH 1
-#define EF1_TX_KER_PORT_LBN 60
-#define EF1_TX_KER_PORT_WIDTH 1
-#define EF1_TX_KER_CONT_LBN 56
-#define EF1_TX_KER_CONT_WIDTH 1
-#define EF1_TX_KER_BYTE_CNT_LBN 32
-#define EF1_TX_KER_BYTE_CNT_WIDTH 24
-#define EF1_TX_KER_BUF_ADR_LBN 0
-#define EF1_TX_KER_BUF_ADR_WIDTH 32
-
-/** TX descriptor FIFO flush */
-#define EF1_TX_DESC_FIFO_FLUSH 0x141ffc
-
-/** RX descriptor FIFO */
-#define EF1_RX_DESC_FIFO 0x145000
-#define EF1_RX_KER_EVQ_LBN 48
-#define EF1_RX_KER_EVQ_WIDTH 12
-#define EF1_RX_KER_IDX_LBN 32
-#define EF1_RX_KER_IDX_WIDTH 16
-#define EF1_RX_KER_BUF_ADR_LBN 0
-#define EF1_RX_KER_BUF_ADR_WIDTH 32
-
-/** RX descriptor FIFO flush */
-#define EF1_RX_DESC_FIFO_FLUSH 0x145ffc
-
-/** CAM */
-#define EF1_CAM_BASE 0x1c0000
-#define EF1_CAM_WTF_DOES_THIS_DO_LBN 0
-#define EF1_CAM_WTF_DOES_THIS_DO_WIDTH 32
-
-/** Event queue pointers */
-#define EF1_EVQ_PTR_BASE 0x260000
-#define EF1_EVQ_SIZE_LBN 29
-#define EF1_EVQ_SIZE_WIDTH 2
-#define EF1_EVQ_SIZE_4K 3
-#define EF1_EVQ_SIZE_2K 2
-#define EF1_EVQ_SIZE_1K 1
-#define EF1_EVQ_SIZE_512 0
-#define EF1_EVQ_BUF_BASE_ID_LBN 0
-#define EF1_EVQ_BUF_BASE_ID_WIDTH 29
-
-/* MAC registers */
-#define EF1002_MAC_REGBANK 0x110000
-#define EF1002_MAC_REGBANK_SIZE 0x1000
-#define EF1002_MAC_REG_SIZE 0x08
-
-/** Offset of a MAC register within EF1002 */
-#define EF1002_MAC_REG( efab, mac_reg ) \
- ( EF1002_MAC_REGBANK + \
- ( (efab)->port * EF1002_MAC_REGBANK_SIZE ) + \
- ( (mac_reg) * EF1002_MAC_REG_SIZE ) )
-
-/* Event queue entries */
-#define EF1_EV_CODE_LBN 20
-#define EF1_EV_CODE_WIDTH 8
-#define EF1_RX_EV_DECODE 0x01
-#define EF1_TX_EV_DECODE 0x02
-#define EF1_TIMER_EV_DECODE 0x0b
-#define EF1_DRV_GEN_EV_DECODE 0x0f
-
-/* Receive events */
-#define EF1_RX_EV_LEN_LBN 48
-#define EF1_RX_EV_LEN_WIDTH 16
-#define EF1_RX_EV_PORT_LBN 17
-#define EF1_RX_EV_PORT_WIDTH 3
-#define EF1_RX_EV_OK_LBN 16
-#define EF1_RX_EV_OK_WIDTH 1
-#define EF1_RX_EV_IDX_LBN 0
-#define EF1_RX_EV_IDX_WIDTH 16
-
-/* Transmit events */
-#define EF1_TX_EV_PORT_LBN 17
-#define EF1_TX_EV_PORT_WIDTH 3
-#define EF1_TX_EV_OK_LBN 16
-#define EF1_TX_EV_OK_WIDTH 1
-#define EF1_TX_EV_IDX_LBN 0
-#define EF1_TX_EV_IDX_WIDTH 16
-
-/* forward decleration */
-static struct efab_mac_operations ef1002_mac_operations;
-
-/* I2C ID of the EEPROM */
-#define EF1_EEPROM_I2C_ID 0x50
-
-/* Offset of MAC address within EEPROM */
-#define EF1_EEPROM_HWADDR_OFFSET 0x0
-
-/**
- * Write dword to EF1002 register
- *
- */
-static inline void ef1002_writel ( struct efab_nic *efab, efab_dword_t *value,
- unsigned int reg ) {
- EFAB_REGDUMP ( "Writing register %x with " EFAB_DWORD_FMT "\n",
- reg, EFAB_DWORD_VAL ( *value ) );
- writel ( value->u32[0], efab->membase + reg );
-}
-
-/**
- * Read dword from an EF1002 register
- *
- */
-static inline void ef1002_readl ( struct efab_nic *efab, efab_dword_t *value,
- unsigned int reg ) {
- value->u32[0] = readl ( efab->membase + reg );
- EFAB_REGDUMP ( "Read from register %x, got " EFAB_DWORD_FMT "\n",
- reg, EFAB_DWORD_VAL ( *value ) );
-}
-
-/**
- * Read dword from an EF1002 register, silently
- *
- */
-static inline void ef1002_readl_silent ( struct efab_nic *efab,
- efab_dword_t *value,
- unsigned int reg ) {
- value->u32[0] = readl ( efab->membase + reg );
-}
-
-/**
- * Get memory base
- *
- */
-static void ef1002_get_membase ( struct efab_nic *efab ) {
- unsigned long membase_phys;
-
- membase_phys = pci_bar_start ( efab->pci, PCI_BASE_ADDRESS_0 );
- efab->membase = ioremap ( membase_phys, 0x800000 );
-}
-
-/** PCI registers to backup/restore over a device reset */
-static const unsigned int efab_pci_reg_addr[] = {
- PCI_COMMAND, 0x0c /* PCI_CACHE_LINE_SIZE */,
- PCI_BASE_ADDRESS_0, PCI_BASE_ADDRESS_1, PCI_BASE_ADDRESS_2,
- PCI_BASE_ADDRESS_3, PCI_ROM_ADDRESS, PCI_INTERRUPT_LINE,
-};
-/** Number of registers in efab_pci_reg_addr */
-#define EFAB_NUM_PCI_REG \
- ( sizeof ( efab_pci_reg_addr ) / sizeof ( efab_pci_reg_addr[0] ) )
-/** PCI configuration space backup */
-struct efab_pci_reg {
- uint32_t reg[EFAB_NUM_PCI_REG];
-};
-
-/*
- * I2C interface and EEPROM
- *
- */
-
-static unsigned long ef1002_i2c_bits[] = {
- [I2C_BIT_SCL] = ( 1 << 30 ),
- [I2C_BIT_SDA] = ( 1 << 31 ),
-};
-
-static void ef1002_i2c_write_bit ( struct bit_basher *basher,
- unsigned int bit_id, unsigned long data ) {
- struct efab_nic *efab = container_of ( basher, struct efab_nic,
- ef1002_i2c.basher );
- unsigned long mask;
- efab_dword_t reg;
+static int
+mdio_clause45_reset_mmd ( struct efab_nic *efab, int mmd )
+{
+ int tries = MDIO45_RESET_TRIES;
+ int ctrl;
- mask = ef1002_i2c_bits[bit_id];
- efab->ef1002_i2c_outputs &= ~mask;
- efab->ef1002_i2c_outputs |= ( data & mask );
- EFAB_POPULATE_DWORD_1 ( reg, EF1_EEPROM, efab->ef1002_i2c_outputs );
- ef1002_writel ( efab, &reg, EF1_EEPROM_REG );
-}
+ falcon_mdio_write ( efab, mmd, MDIO_MMDREG_CTRL1,
+ ( 1 << MDIO_MMDREG_CTRL1_RESET_LBN ) );
-static int ef1002_i2c_read_bit ( struct bit_basher *basher,
- unsigned int bit_id ) {
- struct efab_nic *efab = container_of ( basher, struct efab_nic,
- ef1002_i2c.basher );
- unsigned long mask;
- efab_dword_t reg;
+ /* Wait for the reset bit to clear. */
+ do {
+ mdelay ( MDIO45_RESET_SPINTIME );
- mask = ef1002_i2c_bits[bit_id];
- ef1002_readl ( efab, &reg, EF1_EEPROM_REG );
- return ( EFAB_DWORD_FIELD ( reg, EF1_EEPROM ) & mask );
-}
+ ctrl = falcon_mdio_read ( efab, mmd, MDIO_MMDREG_CTRL1 );
+ if ( ~ctrl & ( 1 << MDIO_MMDREG_CTRL1_RESET_LBN ) )
+ return 0;
+ } while ( --tries );
-static struct bit_basher_operations ef1002_basher_ops = {
- .read = ef1002_i2c_read_bit,
- .write = ef1002_i2c_write_bit,
-};
+ EFAB_ERR ( "Failed to reset mmd %d\n", mmd );
-static void ef1002_init_eeprom ( struct efab_nic *efab ) {
- efab->ef1002_i2c.basher.op = &ef1002_basher_ops;
- init_i2c_bit_basher ( &efab->ef1002_i2c );
- efab->ef1002_eeprom.address = EF1_EEPROM_I2C_ID;
+ return -ETIMEDOUT;
}
-/**
- * Reset device
- *
- */
-static int ef1002_reset ( struct efab_nic *efab ) {
- struct efab_pci_reg pci_reg;
- struct pci_device *pci_dev = efab->pci;
- efab_dword_t reg;
- unsigned int i;
- uint32_t tmp;
-
- /* Back up PCI configuration registers */
- for ( i = 0 ; i < EFAB_NUM_PCI_REG ; i++ ) {
- pci_read_config_dword ( pci_dev, efab_pci_reg_addr[i],
- &pci_reg.reg[i] );
- }
-
- /* Reset the whole device. */
- EFAB_POPULATE_DWORD_1 ( reg, EF1_SW_RESET, 1 );
- ef1002_writel ( efab, &reg, EF1_CTL2_REG );
- mdelay ( 200 );
-
- /* Restore PCI configuration space */
- for ( i = 0 ; i < EFAB_NUM_PCI_REG ; i++ ) {
- pci_write_config_dword ( pci_dev, efab_pci_reg_addr[i],
- pci_reg.reg[i] );
- }
-
- /* Verify PCI configuration space */
- for ( i = 0 ; i < EFAB_NUM_PCI_REG ; i++ ) {
- pci_read_config_dword ( pci_dev, efab_pci_reg_addr[i], &tmp );
- if ( tmp != pci_reg.reg[i] ) {
- EFAB_LOG ( "PCI restore failed on register %02x "
- "(is %08lx, should be %08lx); reboot\n",
- i, tmp, pci_reg.reg[i] );
- return 0;
+static int
+mdio_clause45_links_ok(struct efab_nic *efab )
+{
+ int status, good;
+ int ok = 1;
+ int mmd = 0;
+ int mmd_mask = efab->phy_op->mmds;
+
+ while (mmd_mask) {
+ if (mmd_mask & 1) {
+ /* Double reads because link state is latched, and a
+ * read moves the current state into the register */
+ status = falcon_mdio_read ( efab, mmd,
+ MDIO_MMDREG_STAT1 );
+ status = falcon_mdio_read ( efab, mmd,
+ MDIO_MMDREG_STAT1 );
+
+ good = status & (1 << MDIO_MMDREG_STAT1_LINK_LBN);
+ ok = ok && good;
}
+ mmd_mask = (mmd_mask >> 1);
+ mmd++;
}
-
- /* Verify device reset complete */
- ef1002_readl ( efab, &reg, EF1_CTR_GEN_STATUS0_REG );
- if ( EFAB_DWORD_IS_ALL_ONES ( reg ) ) {
- EFAB_ERR ( "Reset failed\n" );
- return 0;
- }
-
- return 1;
-}
-
-/**
- * Initialise NIC
- *
- */
-static int ef1002_init_nic ( struct efab_nic *efab ) {
- efab_dword_t reg;
-
- /* patch in the MAC operations */
- efab->mac_op = &ef1002_mac_operations;
-
- /* No idea what CAM is, but the 'datasheet' says that we have
- * to write these values in at start of day
- */
- EFAB_POPULATE_DWORD_1 ( reg, EF1_CAM_WTF_DOES_THIS_DO, 0x6 );
- ef1002_writel ( efab, &reg, EF1_CAM_BASE + 0x20018 );
- udelay ( 1000 );
- EFAB_POPULATE_DWORD_1 ( reg, EF1_CAM_WTF_DOES_THIS_DO, 0x01000000 );
- ef1002_writel ( efab, &reg, EF1_CAM_BASE + 0x00018 );
- udelay ( 1000 );
-
- /* General control register 0 */
- ef1002_readl ( efab, &reg, EF1_CTR_GEN_STATUS0_REG );
- EFAB_SET_DWORD_FIELD ( reg, EF1_MASTER_EVENTS, 0 );
- EFAB_SET_DWORD_FIELD ( reg, EF1_TX_ENGINE_EN, 0 );
- EFAB_SET_DWORD_FIELD ( reg, EF1_RX_ENGINE_EN, 0 );
- EFAB_SET_DWORD_FIELD ( reg, EF1_TURBO2, 1 );
- EFAB_SET_DWORD_FIELD ( reg, EF1_TURBO1, 1 );
- EFAB_SET_DWORD_FIELD ( reg, EF1_TURBO3, 1 );
- EFAB_SET_DWORD_FIELD ( reg, EF1_CAM_ENABLE, 1 );
- ef1002_writel ( efab, &reg, EF1_CTR_GEN_STATUS0_REG );
- udelay ( 1000 );
-
- /* General control register 2 */
- ef1002_readl ( efab, &reg, EF1_CTL2_REG );
- EFAB_SET_DWORD_FIELD ( reg, EF1_PLL_TRAP, 1 );
- EFAB_SET_DWORD_FIELD ( reg, EF1_MEM_MAP_4MB, 0 );
- EFAB_SET_DWORD_FIELD ( reg, EF1_EV_INTR_CLR_WRITE, 0 );
- EFAB_SET_DWORD_FIELD ( reg, EF1_BURST_MERGE, 0 );
- EFAB_SET_DWORD_FIELD ( reg, EF1_CLEAR_NULL_PAD, 1 );
- EFAB_SET_DWORD_FIELD ( reg, EF1_INTR_AFTER_EVENT, 1 );
- ef1002_writel ( efab, &reg, EF1_CTL2_REG );
- udelay ( 1000 );
-
- /* Enable RX DMA */
- ef1002_readl ( efab, &reg, EF1_DMA_RX_CSR_REG );
- EFAB_SET_DWORD_FIELD ( reg, EF1_DMA_RX_CSR_ENABLE, 1 );
- EFAB_SET_DWORD_FIELD ( reg, EF1_DMA_RX_BELOW_1MB_EN, 1 );
- EFAB_SET_DWORD_FIELD ( reg, EF1_DMA_RX_ABOVE_1GB_EN, 1 );
- ef1002_writel ( efab, &reg, EF1_DMA_RX_CSR_REG );
- udelay ( 1000 );
-
- /* Enable TX DMA */
- ef1002_readl ( efab, &reg, EF1_DMA_TX_CSR_REG );
- EFAB_SET_DWORD_FIELD ( reg, EF1_DMA_TX_CSR_CHAIN_EN, 1 );
- EFAB_SET_DWORD_FIELD ( reg, EF1_DMA_TX_CSR_ENABLE, 0 /* ?? */ );
- EFAB_SET_DWORD_FIELD ( reg, EF1_DMA_TX_CSR_INT_EN, 0 /* ?? */ );
- ef1002_writel ( efab, &reg, EF1_DMA_TX_CSR_REG );
- udelay ( 1000 );
-
- /* Disconnect the JTAG chain. Read-modify-write is impossible
- * on the I2C control bits, since reading gives the state of
- * the line inputs rather than the last written state.
- */
- ef1002_readl ( efab, &reg, EF1_EEPROM_REG );
- EFAB_SET_DWORD_FIELD ( reg, EF1_EEPROM_SDA, 1 );
- EFAB_SET_DWORD_FIELD ( reg, EF1_EEPROM_SCL, 1 );
- EFAB_SET_DWORD_FIELD ( reg, EF1_JTAG_DISCONNECT, 1 );
- ef1002_writel ( efab, &reg, EF1_EEPROM_REG );
- udelay ( 10 );
-
- /* Flush descriptor queues */
- EFAB_ZERO_DWORD ( reg );
- ef1002_writel ( efab, &reg, EF1_RX_DESC_FIFO_FLUSH );
- ef1002_writel ( efab, &reg, EF1_TX_DESC_FIFO_FLUSH );
- wmb();
- udelay ( 10000 );
-
- /* Reset MAC */
- efab->mac_op->reset ( efab );
-
- /* Attach I2C bus */
- ef1002_init_eeprom ( efab );
-
- return 1;
-}
-
-/**
- * Read MAC address from EEPROM
- *
- */
-static int ef1002_read_eeprom ( struct efab_nic *efab ) {
- struct i2c_interface *i2c = &efab->ef1002_i2c.i2c;
- struct i2c_device *i2cdev = &efab->ef1002_eeprom;
-
- if ( i2c->read ( i2c, i2cdev, EF1_EEPROM_HWADDR_OFFSET,
- efab->mac_addr, sizeof ( efab->mac_addr ) ) != 0 )
- return 0;
-
- efab->mac_addr[ETH_ALEN-1] += efab->port;
-
- return 1;
-}
-
-/** RX descriptor */
-typedef efab_qword_t ef1002_rx_desc_t;
-
-/**
- * Build RX descriptor
- *
- */
-static void ef1002_build_rx_desc ( struct efab_nic *efab,
- struct efab_rx_buf *rx_buf ) {
- ef1002_rx_desc_t rxd;
-
- EFAB_POPULATE_QWORD_3 ( rxd,
- EF1_RX_KER_EVQ, 0,
- EF1_RX_KER_IDX, rx_buf->id,
- EF1_RX_KER_BUF_ADR,
- virt_to_bus ( rx_buf->addr ) );
- ef1002_writel ( efab, &rxd.dword[0], EF1_RX_DESC_FIFO + 0 );
- wmb();
- ef1002_writel ( efab, &rxd.dword[1], EF1_RX_DESC_FIFO + 4 );
- udelay ( 10 );
-}
-
-/**
- * Update RX descriptor write pointer
- *
- */
-static void ef1002_notify_rx_desc ( struct efab_nic *efab __unused ) {
- /* Nothing to do */
+ return ok;
}
-/** TX descriptor */
-typedef efab_oword_t ef1002_tx_desc_t;
-
-/**
- * Build TX descriptor
- *
- */
-static void ef1002_build_tx_desc ( struct efab_nic *efab,
- struct efab_tx_buf *tx_buf ) {
- ef1002_tx_desc_t txd;
-
- EFAB_POPULATE_OWORD_7 ( txd,
- EF1_TX_KER_EVQ, 0,
- EF1_TX_KER_IDX, tx_buf->id,
- EF1_TX_KER_MODE, 0 /* IP mode */,
- EF1_TX_KER_PORT, efab->port,
- EF1_TX_KER_CONT, 0,
- EF1_TX_KER_BYTE_CNT, tx_buf->len,
- EF1_TX_KER_BUF_ADR,
- virt_to_bus ( tx_buf->addr ) );
-
- ef1002_writel ( efab, &txd.dword[0], EF1_TX_DESC_FIFO + 0 );
- ef1002_writel ( efab, &txd.dword[1], EF1_TX_DESC_FIFO + 4 );
- wmb();
- ef1002_writel ( efab, &txd.dword[2], EF1_TX_DESC_FIFO + 8 );
- udelay ( 10 );
-}
-
-/**
- * Update TX descriptor write pointer
- *
- */
-static void ef1002_notify_tx_desc ( struct efab_nic *efab __unused ) {
- /* Nothing to do */
-}
-
-/** An event */
-typedef efab_qword_t ef1002_event_t;
-
-/**
- * Retrieve event from event queue
- *
- */
-static int ef1002_fetch_event ( struct efab_nic *efab,
- struct efab_event *event ) {
- efab_dword_t reg;
- int ev_code;
- int words;
-
- /* Check event FIFO depth */
- ef1002_readl_silent ( efab, &reg, EF1_EVENT_FIFO_COUNT_REG );
- words = EFAB_DWORD_FIELD ( reg, EF1_EV_COUNT );
- if ( ! words )
- return 0;
-
- /* Read event data */
- ef1002_readl ( efab, &reg, EF1_EVENT_FIFO_REG );
- DBG ( "Event is " EFAB_DWORD_FMT "\n", EFAB_DWORD_VAL ( reg ) );
-
- /* Decode event */
- ev_code = EFAB_DWORD_FIELD ( reg, EF1_EV_CODE );
- event->drop = 0;
- switch ( ev_code ) {
- case EF1_TX_EV_DECODE:
- event->type = EFAB_EV_TX;
- break;
- case EF1_RX_EV_DECODE:
- event->type = EFAB_EV_RX;
- event->rx_id = EFAB_DWORD_FIELD ( reg, EF1_RX_EV_IDX );
- /* RX len not available via event FIFO */
- event->rx_len = ETH_FRAME_LEN;
- break;
- case EF1_TIMER_EV_DECODE:
- /* These are safe to ignore. We seem to get some at
- * start of day, presumably due to the timers starting
- * up with random contents.
- */
- event->type = EFAB_EV_NONE;
- break;
- default:
- EFAB_ERR ( "Unknown event type %d\n", ev_code );
- event->type = EFAB_EV_NONE;
+static int
+mdio_clause45_check_mmds ( struct efab_nic *efab )
+{
+ int mmd = 0;
+ int devices = falcon_mdio_read ( efab, MDIO_MMD_PHYXS,
+ MDIO_MMDREG_DEVS0 );
+ int mmd_mask = efab->phy_op->mmds;
+
+ /* Check all the expected MMDs are present */
+ if ( devices < 0 ) {
+ EFAB_ERR ( "Failed to read devices present\n" );
+ return -EIO;
}
-
- /* Clear any pending interrupts */
- ef1002_readl ( efab, &reg, EF1_IRQ_SRC_REG );
-
- return 1;
-}
-
-/**
- * Enable/disable interrupts
- *
- */
-static void ef1002_mask_irq ( struct efab_nic *efab, int enabled ) {
- efab_dword_t irq_mask;
-
- EFAB_POPULATE_DWORD_2 ( irq_mask,
- EF1_IRQ_SERR, enabled,
- EF1_IRQ_EVQ, enabled );
- ef1002_writel ( efab, &irq_mask, EF1_IRQ_MASK_REG );
-}
-
-/**
- * Generate interrupt
- *
- */
-static void ef1002_generate_irq ( struct efab_nic *efab ) {
- ef1002_event_t test_event;
-
- EFAB_POPULATE_QWORD_1 ( test_event,
- EF1_EV_CODE, EF1_DRV_GEN_EV_DECODE );
- ef1002_writel ( efab, &test_event.dword[0], EF1_EVT3_REG );
-}
-
-/**
- * Write dword to an EF1002 MAC register
- *
- */
-static void ef1002_mac_writel ( struct efab_nic *efab,
- efab_dword_t *value, unsigned int mac_reg ) {
- ef1002_writel ( efab, value, EF1002_MAC_REG ( efab, mac_reg ) );
-}
-
-/**
- * Read dword from an EF1002 MAC register
- *
- */
-static void ef1002_mac_readl ( struct efab_nic *efab,
- efab_dword_t *value, unsigned int mac_reg ) {
- ef1002_readl ( efab, value, EF1002_MAC_REG ( efab, mac_reg ) );
-}
-
-/**
- * Initialise MAC
- *
- */
-static int ef1002_init_mac ( struct efab_nic *efab ) {
- static struct efab_mentormac_parameters ef1002_mentormac_params = {
- .gmf_cfgfrth = 0x13,
- .gmf_cfgftth = 0x10,
- .gmf_cfghwmft = 0x555,
- .gmf_cfghwm = 0x2a,
- .gmf_cfglwm = 0x15,
- };
- efab_dword_t reg;
- unsigned int mac_clk;
-
- /* Initialise PHY */
- alaska_init ( efab );
-
- /* Initialise MAC */
- mentormac_init ( efab, &ef1002_mentormac_params );
-
- /* Write Level 5 watermark register */
- EFAB_POPULATE_DWORD_1 ( reg, EF1_L5WM, 0x10040000 );
- efab->mac_op->mac_writel ( efab, &reg, EF1_GMF_L5WM_REG_MAC );
- udelay ( 10 );
-
- /* Set MAC clock speed */
- ef1002_readl ( efab, &reg, EF1_GM_MAC_CLK_REG );
- mac_clk = ( efab->link_options & LPA_1000 ) ? 0 : 1;
- if ( efab->port == 0 ) {
- EFAB_SET_DWORD_FIELD ( reg, EF1_GM_PORT0_MAC_CLK, mac_clk );
- } else {
- EFAB_SET_DWORD_FIELD ( reg, EF1_GM_PORT1_MAC_CLK, mac_clk );
+ if ( ( devices & mmd_mask ) != mmd_mask ) {
+ EFAB_ERR ( "required MMDs not present: got %x, wanted %x\n",
+ devices, mmd_mask );
+ return -EIO;
}
- ef1002_writel ( efab, &reg, EF1_GM_MAC_CLK_REG );
- udelay ( 10 );
- return 1;
-}
+ /* Check all required MMDs are responding and happy. */
+ while ( mmd_mask ) {
+ if ( mmd_mask & 1 ) {
+ efab_dword_t reg;
+ int status;
+ reg.opaque = falcon_mdio_read ( efab, mmd,
+ MDIO_MMDREG_STAT2 );
+ status = EFAB_DWORD_FIELD ( reg,
+ MDIO_MMDREG_STAT2_PRESENT );
+ if ( status != MDIO_MMDREG_STAT2_PRESENT_VAL ) {
-/**
- * Reset MAC
- *
- */
-static int ef1002_reset_mac ( struct efab_nic *efab ) {
- mentormac_reset ( efab );
- return 1;
-}
-/** MDIO write */
-static void ef1002_mdio_write ( struct efab_nic *efab, int location,
- int value ) {
- mentormac_mdio_write ( efab, efab->port + 2, location, value );
-}
+ return -EIO;
+ }
+ }
+ mmd_mask >>= 1;
+ mmd++;
+ }
-/** MDIO read */
-static int ef1002_mdio_read ( struct efab_nic *efab, int location ) {
- return mentormac_mdio_read ( efab, efab->port + 2, location );
+ return 0;
}
-static struct efab_operations ef1002_operations = {
- .get_membase = ef1002_get_membase,
- .reset = ef1002_reset,
- .init_nic = ef1002_init_nic,
- .read_eeprom = ef1002_read_eeprom,
- .build_rx_desc = ef1002_build_rx_desc,
- .notify_rx_desc = ef1002_notify_rx_desc,
- .build_tx_desc = ef1002_build_tx_desc,
- .notify_tx_desc = ef1002_notify_tx_desc,
- .fetch_event = ef1002_fetch_event,
- .mask_irq = ef1002_mask_irq,
- .generate_irq = ef1002_generate_irq,
- .mdio_write = ef1002_mdio_write,
- .mdio_read = ef1002_mdio_read,
-};
-
-static struct efab_mac_operations ef1002_mac_operations = {
- .mac_writel = ef1002_mac_writel,
- .mac_readl = ef1002_mac_readl,
- .init = ef1002_init_mac,
- .reset = ef1002_reset_mac,
-};
-
-/**************************************************************************
- *
- * Falcon routines
- *
- **************************************************************************
- */
-
/* I/O BAR address register */
#define FCN_IOM_IND_ADR_REG 0x0
/* I/O BAR data register */
#define FCN_IOM_IND_DAT_REG 0x4
+/* Address region register */
+#define FCN_ADR_REGION_REG_KER 0x00
+#define FCN_ADR_REGION0_LBN 0
+#define FCN_ADR_REGION0_WIDTH 18
+#define FCN_ADR_REGION1_LBN 32
+#define FCN_ADR_REGION1_WIDTH 18
+#define FCN_ADR_REGION2_LBN 64
+#define FCN_ADR_REGION2_WIDTH 18
+#define FCN_ADR_REGION3_LBN 96
+#define FCN_ADR_REGION3_WIDTH 18
+
/* Interrupt enable register */
#define FCN_INT_EN_REG_KER 0x0010
#define FCN_MEM_PERR_INT_EN_KER_LBN 5
@@ -1505,11 +439,25 @@ static struct efab_mac_operations ef1002_mac_operations = {
#define FCN_INT_ADR_KER_LBN 0
#define FCN_INT_ADR_KER_WIDTH EFAB_DMA_TYPE_WIDTH ( 64 )
-/* Interrupt acknowledge register */
-#define FCN_INT_ACK_KER_REG 0x0050
+/* Interrupt status register (B0 only) */
+#define INT_ISR0_B0 0x90
+#define INT_ISR1_B0 0xA0
+
+/* Interrupt acknowledge register (A0/A1 only) */
+#define FCN_INT_ACK_KER_REG_A1 0x0050
+#define INT_ACK_DUMMY_DATA_LBN 0
+#define INT_ACK_DUMMY_DATA_WIDTH 32
+
+/* Interrupt acknowledge work-around register (A0/A1 only )*/
+#define WORK_AROUND_BROKEN_PCI_READS_REG_KER_A1 0x0070
+
+/* Hardware initialisation register */
+#define FCN_HW_INIT_REG_KER 0x00c0
+#define FCN_BCSR_TARGET_MASK_LBN 101
+#define FCN_BCSR_TARGET_MASK_WIDTH 4
/* SPI host command register */
-#define FCN_EE_SPI_HCMD_REG_KER 0x0100
+#define FCN_EE_SPI_HCMD_REG 0x0100
#define FCN_EE_SPI_HCMD_CMD_EN_LBN 31
#define FCN_EE_SPI_HCMD_CMD_EN_WIDTH 1
#define FCN_EE_WR_TIMER_ACTIVE_LBN 28
@@ -1532,14 +480,14 @@ static struct efab_mac_operations ef1002_mac_operations = {
#define FCN_EE_SPI_HCMD_ENC_WIDTH 8
/* SPI host address register */
-#define FCN_EE_SPI_HADR_REG_KER 0x0110
+#define FCN_EE_SPI_HADR_REG 0x0110
#define FCN_EE_SPI_HADR_DUBYTE_LBN 24
#define FCN_EE_SPI_HADR_DUBYTE_WIDTH 8
#define FCN_EE_SPI_HADR_ADR_LBN 0
#define FCN_EE_SPI_HADR_ADR_WIDTH 24
/* SPI host data register */
-#define FCN_EE_SPI_HDATA_REG_KER 0x0120
+#define FCN_EE_SPI_HDATA_REG 0x0120
#define FCN_EE_SPI_HDATA3_LBN 96
#define FCN_EE_SPI_HDATA3_WIDTH 32
#define FCN_EE_SPI_HDATA2_LBN 64
@@ -1549,89 +497,130 @@ static struct efab_mac_operations ef1002_mac_operations = {
#define FCN_EE_SPI_HDATA0_LBN 0
#define FCN_EE_SPI_HDATA0_WIDTH 32
-/* VPI configuration register */
-#define FCN_VPD_CONFIG_REG_KER 0x0140
-#define FCN_VPD_9BIT_LBN 1
-#define FCN_VPD_9BIT_WIDTH 1
+/* VPD Config 0 Register register */
+#define FCN_EE_VPD_CFG_REG 0x0140
+#define FCN_EE_VPD_EN_LBN 0
+#define FCN_EE_VPD_EN_WIDTH 1
+#define FCN_EE_VPD_EN_AD9_MODE_LBN 1
+#define FCN_EE_VPD_EN_AD9_MODE_WIDTH 1
+#define FCN_EE_EE_CLOCK_DIV_LBN 112
+#define FCN_EE_EE_CLOCK_DIV_WIDTH 7
+#define FCN_EE_SF_CLOCK_DIV_LBN 120
+#define FCN_EE_SF_CLOCK_DIV_WIDTH 7
+
/* NIC status register */
#define FCN_NIC_STAT_REG 0x0200
-#define ONCHIP_SRAM_LBN 16
-#define ONCHIP_SRAM_WIDTH 1
-#define SF_PRST_LBN 9
-#define SF_PRST_WIDTH 1
-#define EE_PRST_LBN 8
-#define EE_PRST_WIDTH 1
-#define EE_STRAP_LBN 7
-#define EE_STRAP_WIDTH 1
-#define PCI_PCIX_MODE_LBN 4
-#define PCI_PCIX_MODE_WIDTH 3
-#define PCI_PCIX_MODE_PCI33_DECODE 0
-#define PCI_PCIX_MODE_PCI66_DECODE 1
-#define PCI_PCIX_MODE_PCIX66_DECODE 5
-#define PCI_PCIX_MODE_PCIX100_DECODE 6
-#define PCI_PCIX_MODE_PCIX133_DECODE 7
-#define STRAP_ISCSI_EN_LBN 3
-#define STRAP_ISCSI_EN_WIDTH 1
-#define STRAP_PINS_LBN 0
-#define STRAP_PINS_WIDTH 3
-/* These bit definitions are extrapolated from the list of numerical
- * values for STRAP_PINS. If you want a laugh, read the datasheet's
- * definition for when bits 2:0 are set to 7.
- */
-#define STRAP_10G_LBN 2
-#define STRAP_10G_WIDTH 1
-#define STRAP_DUAL_PORT_LBN 1
-#define STRAP_DUAL_PORT_WIDTH 1
-#define STRAP_PCIE_LBN 0
-#define STRAP_PCIE_WIDTH 1
+#define FCN_ONCHIP_SRAM_LBN 16
+#define FCN_ONCHIP_SRAM_WIDTH 1
+#define FCN_SF_PRST_LBN 9
+#define FCN_SF_PRST_WIDTH 1
+#define FCN_EE_PRST_LBN 8
+#define FCN_EE_PRST_WIDTH 1
+#define FCN_EE_STRAP_LBN 7
+#define FCN_EE_STRAP_WIDTH 1
+#define FCN_PCI_PCIX_MODE_LBN 4
+#define FCN_PCI_PCIX_MODE_WIDTH 3
+#define FCN_PCI_PCIX_MODE_PCI33_DECODE 0
+#define FCN_PCI_PCIX_MODE_PCI66_DECODE 1
+#define FCN_PCI_PCIX_MODE_PCIX66_DECODE 5
+#define FCN_PCI_PCIX_MODE_PCIX100_DECODE 6
+#define FCN_PCI_PCIX_MODE_PCIX133_DECODE 7
+#define FCN_STRAP_ISCSI_EN_LBN 3
+#define FCN_STRAP_ISCSI_EN_WIDTH 1
+#define FCN_STRAP_PINS_LBN 0
+#define FCN_STRAP_PINS_WIDTH 3
+#define FCN_STRAP_10G_LBN 2
+#define FCN_STRAP_10G_WIDTH 1
+#define FCN_STRAP_DUAL_PORT_LBN 1
+#define FCN_STRAP_DUAL_PORT_WIDTH 1
+#define FCN_STRAP_PCIE_LBN 0
+#define FCN_STRAP_PCIE_WIDTH 1
+
+/* Falcon revisions */
+#define FALCON_REV_A0 0
+#define FALCON_REV_A1 1
+#define FALCON_REV_B0 2
/* GPIO control register */
#define FCN_GPIO_CTL_REG_KER 0x0210
+#define FCN_GPIO_CTL_REG_KER 0x0210
+
+#define FCN_GPIO3_OEN_LBN 27
+#define FCN_GPIO3_OEN_WIDTH 1
+#define FCN_GPIO2_OEN_LBN 26
+#define FCN_GPIO2_OEN_WIDTH 1
+#define FCN_GPIO1_OEN_LBN 25
+#define FCN_GPIO1_OEN_WIDTH 1
+#define FCN_GPIO0_OEN_LBN 24
+#define FCN_GPIO0_OEN_WIDTH 1
+
+#define FCN_GPIO3_OUT_LBN 19
+#define FCN_GPIO3_OUT_WIDTH 1
+#define FCN_GPIO2_OUT_LBN 18
+#define FCN_GPIO2_OUT_WIDTH 1
+#define FCN_GPIO1_OUT_LBN 17
+#define FCN_GPIO1_OUT_WIDTH 1
+#define FCN_GPIO0_OUT_LBN 16
+#define FCN_GPIO0_OUT_WIDTH 1
+
+#define FCN_GPIO3_IN_LBN 11
+#define FCN_GPIO3_IN_WIDTH 1
+#define FCN_GPIO2_IN_LBN 10
+#define FCN_GPIO2_IN_WIDTH 1
+#define FCN_GPIO1_IN_LBN 9
+#define FCN_GPIO1_IN_WIDTH 1
+#define FCN_GPIO0_IN_LBN 8
+#define FCN_GPIO0_IN_WIDTH 1
+
#define FCN_FLASH_PRESENT_LBN 7
#define FCN_FLASH_PRESENT_WIDTH 1
#define FCN_EEPROM_PRESENT_LBN 6
#define FCN_EEPROM_PRESENT_WIDTH 1
+#define FCN_BOOTED_USING_NVDEVICE_LBN 3
+#define FCN_BOOTED_USING_NVDEVICE_WIDTH 1
+
+/* Defines for extra non-volatile storage */
+#define FCN_NV_MAGIC_NUMBER 0xFA1C
/* Global control register */
#define FCN_GLB_CTL_REG_KER 0x0220
-#define EXT_PHY_RST_CTL_LBN 63
-#define EXT_PHY_RST_CTL_WIDTH 1
-#define PCIE_SD_RST_CTL_LBN 61
-#define PCIE_SD_RST_CTL_WIDTH 1
-#define PCIX_RST_CTL_LBN 60
-#define PCIX_RST_CTL_WIDTH 1
-#define PCIE_STCK_RST_CTL_LBN 59
-#define PCIE_STCK_RST_CTL_WIDTH 1
-#define PCIE_NSTCK_RST_CTL_LBN 58
-#define PCIE_NSTCK_RST_CTL_WIDTH 1
-#define PCIE_CORE_RST_CTL_LBN 57
-#define PCIE_CORE_RST_CTL_WIDTH 1
-#define EE_RST_CTL_LBN 49
-#define EE_RST_CTL_WIDTH 1
-#define CS_RST_CTL_LBN 48
-#define CS_RST_CTL_WIDTH 1
-#define RST_EXT_PHY_LBN 31
-#define RST_EXT_PHY_WIDTH 1
-#define INT_RST_DUR_LBN 4
-#define INT_RST_DUR_WIDTH 3
-#define EXT_PHY_RST_DUR_LBN 1
-#define EXT_PHY_RST_DUR_WIDTH 3
-#define SWRST_LBN 0
-#define SWRST_WIDTH 1
+#define FCN_EXT_PHY_RST_CTL_LBN 63
+#define FCN_EXT_PHY_RST_CTL_WIDTH 1
+#define FCN_PCIE_SD_RST_CTL_LBN 61
+#define FCN_PCIE_SD_RST_CTL_WIDTH 1
+#define FCN_PCIE_STCK_RST_CTL_LBN 59
+#define FCN_PCIE_STCK_RST_CTL_WIDTH 1
+#define FCN_PCIE_NSTCK_RST_CTL_LBN 58
+#define FCN_PCIE_NSTCK_RST_CTL_WIDTH 1
+#define FCN_PCIE_CORE_RST_CTL_LBN 57
+#define FCN_PCIE_CORE_RST_CTL_WIDTH 1
+#define FCN_EE_RST_CTL_LBN 49
+#define FCN_EE_RST_CTL_WIDTH 1
+#define FCN_RST_EXT_PHY_LBN 31
+#define FCN_RST_EXT_PHY_WIDTH 1
+#define FCN_EXT_PHY_RST_DUR_LBN 1
+#define FCN_EXT_PHY_RST_DUR_WIDTH 3
+#define FCN_SWRST_LBN 0
+#define FCN_SWRST_WIDTH 1
#define INCLUDE_IN_RESET 0
#define EXCLUDE_FROM_RESET 1
/* FPGA build version */
-#define ALTERA_BUILD_REG_KER 0x0300
-#define VER_MAJOR_LBN 24
-#define VER_MAJOR_WIDTH 8
-#define VER_MINOR_LBN 16
-#define VER_MINOR_WIDTH 8
-#define VER_BUILD_LBN 0
-#define VER_BUILD_WIDTH 16
-#define VER_ALL_LBN 0
-#define VER_ALL_WIDTH 32
+#define FCN_ALTERA_BUILD_REG_KER 0x0300
+#define FCN_VER_MAJOR_LBN 24
+#define FCN_VER_MAJOR_WIDTH 8
+#define FCN_VER_MINOR_LBN 16
+#define FCN_VER_MINOR_WIDTH 8
+#define FCN_VER_BUILD_LBN 0
+#define FCN_VER_BUILD_WIDTH 16
+#define FCN_VER_ALL_LBN 0
+#define FCN_VER_ALL_WIDTH 32
+
+/* Spare EEPROM bits register (flash 0x390) */
+#define FCN_SPARE_REG_KER 0x310
+#define FCN_MEM_PERR_EN_TX_DATA_LBN 72
+#define FCN_MEM_PERR_EN_TX_DATA_WIDTH 2
/* Timer table for kernel access */
#define FCN_TIMER_CMD_REG_KER 0x420
@@ -1657,10 +646,65 @@ static struct efab_mac_operations ef1002_mac_operations = {
#define FCN_SRM_TX_DC_BASE_ADR_LBN 0
#define FCN_SRM_TX_DC_BASE_ADR_WIDTH 21
+/* SRAM configuration register */
+#define FCN_SRM_CFG_REG_KER 0x630
+#define FCN_SRAM_OOB_ADR_INTEN_LBN 5
+#define FCN_SRAM_OOB_ADR_INTEN_WIDTH 1
+#define FCN_SRAM_OOB_BUF_INTEN_LBN 4
+#define FCN_SRAM_OOB_BUF_INTEN_WIDTH 1
+#define FCN_SRAM_OOB_BT_INIT_EN_LBN 3
+#define FCN_SRAM_OOB_BT_INIT_EN_WIDTH 1
+#define FCN_SRM_NUM_BANK_LBN 2
+#define FCN_SRM_NUM_BANK_WIDTH 1
+#define FCN_SRM_BANK_SIZE_LBN 0
+#define FCN_SRM_BANK_SIZE_WIDTH 2
+#define FCN_SRM_NUM_BANKS_AND_BANK_SIZE_LBN 0
+#define FCN_SRM_NUM_BANKS_AND_BANK_SIZE_WIDTH 3
+
+#define FCN_RX_CFG_REG_KER 0x800
+#define FCN_RX_INGR_EN_B0_LBN 47
+#define FCN_RX_INGR_EN_B0_WIDTH 1
+#define FCN_RX_USR_BUF_SIZE_B0_LBN 19
+#define FCN_RX_USR_BUF_SIZE_B0_WIDTH 9
+#define FCN_RX_XON_MAC_TH_B0_LBN 10
+#define FCN_RX_XON_MAC_TH_B0_WIDTH 9
+#define FCN_RX_XOFF_MAC_TH_B0_LBN 1
+#define FCN_RX_XOFF_MAC_TH_B0_WIDTH 9
+#define FCN_RX_XOFF_MAC_EN_B0_LBN 0
+#define FCN_RX_XOFF_MAC_EN_B0_WIDTH 1
+#define FCN_RX_USR_BUF_SIZE_A1_LBN 11
+#define FCN_RX_USR_BUF_SIZE_A1_WIDTH 9
+#define FCN_RX_XON_MAC_TH_A1_LBN 6
+#define FCN_RX_XON_MAC_TH_A1_WIDTH 5
+#define FCN_RX_XOFF_MAC_TH_A1_LBN 1
+#define FCN_RX_XOFF_MAC_TH_A1_WIDTH 5
+#define FCN_RX_XOFF_MAC_EN_A1_LBN 0
+#define FCN_RX_XOFF_MAC_EN_A1_WIDTH 1
+
+#define FCN_RX_USR_BUF_SIZE_A1_LBN 11
+#define FCN_RX_USR_BUF_SIZE_A1_WIDTH 9
+#define FCN_RX_XOFF_MAC_EN_A1_LBN 0
+#define FCN_RX_XOFF_MAC_EN_A1_WIDTH 1
+
/* Receive filter control register */
#define FCN_RX_FILTER_CTL_REG_KER 0x810
+#define FCN_UDP_FULL_SRCH_LIMIT_LBN 32
+#define FCN_UDP_FULL_SRCH_LIMIT_WIDTH 8
#define FCN_NUM_KER_LBN 24
#define FCN_NUM_KER_WIDTH 2
+#define FCN_UDP_WILD_SRCH_LIMIT_LBN 16
+#define FCN_UDP_WILD_SRCH_LIMIT_WIDTH 8
+#define FCN_TCP_WILD_SRCH_LIMIT_LBN 8
+#define FCN_TCP_WILD_SRCH_LIMIT_WIDTH 8
+#define FCN_TCP_FULL_SRCH_LIMIT_LBN 0
+#define FCN_TCP_FULL_SRCH_LIMIT_WIDTH 8
+
+/* RX queue flush register */
+#define FCN_RX_FLUSH_DESCQ_REG_KER 0x0820
+#define FCN_RX_FLUSH_DESCQ_CMD_LBN 24
+#define FCN_RX_FLUSH_DESCQ_CMD_WIDTH 1
+#define FCN_RX_FLUSH_DESCQ_LBN 0
+#define FCN_RX_FLUSH_DESCQ_WIDTH 12
/* Receive descriptor update register */
#define FCN_RX_DESC_UPD_REG_KER 0x0830
@@ -1675,6 +719,26 @@ static struct efab_mac_operations ef1002_mac_operations = {
#define FCN_RX_DC_SIZE_LBN 0
#define FCN_RX_DC_SIZE_WIDTH 2
+#define FCN_RX_SELF_RST_REG_KER 0x890
+#define FCN_RX_ISCSI_DIS_LBN 17
+#define FCN_RX_ISCSI_DIS_WIDTH 1
+#define FCN_RX_NODESC_WAIT_DIS_LBN 9
+#define FCN_RX_NODESC_WAIT_DIS_WIDTH 1
+#define FCN_RX_RECOVERY_EN_LBN 8
+#define FCN_RX_RECOVERY_EN_WIDTH 1
+
+/* TX queue flush register */
+#define FCN_TX_FLUSH_DESCQ_REG_KER 0x0a00
+#define FCN_TX_FLUSH_DESCQ_CMD_LBN 12
+#define FCN_TX_FLUSH_DESCQ_CMD_WIDTH 1
+#define FCN_TX_FLUSH_DESCQ_LBN 0
+#define FCN_TX_FLUSH_DESCQ_WIDTH 12
+
+/* Transmit configuration register 2 */
+#define FCN_TX_CFG2_REG_KER 0xa80
+#define FCN_TX_DIS_NON_IP_EV_LBN 17
+#define FCN_TX_DIS_NON_IP_EV_WIDTH 1
+
/* Transmit descriptor update register */
#define FCN_TX_DESC_UPD_REG_KER 0x0a10
#define FCN_TX_DESC_WPTR_LBN 96
@@ -1704,6 +768,8 @@ static struct efab_mac_operations ef1002_mac_operations = {
#define FCN_MD_GC_WIDTH 1
#define FCN_MD_RIC_LBN 2
#define FCN_MD_RIC_WIDTH 1
+#define FCN_MD_RDC_LBN 1
+#define FCN_MD_RDC_WIDTH 1
#define FCN_MD_WRC_LBN 0
#define FCN_MD_WRC_WIDTH 1
@@ -1721,6 +787,14 @@ static struct efab_mac_operations ef1002_mac_operations = {
/* PHY management status & mask register */
#define FCN_MD_STAT_REG_KER 0xc50
+#define FCN_MD_PINT_LBN 4
+#define FCN_MD_PINT_WIDTH 1
+#define FCN_MD_DONE_LBN 3
+#define FCN_MD_DONE_WIDTH 1
+#define FCN_MD_BSERR_LBN 2
+#define FCN_MD_BSERR_WIDTH 1
+#define FCN_MD_LNFL_LBN 1
+#define FCN_MD_LNFL_WIDTH 1
#define FCN_MD_BSY_LBN 0
#define FCN_MD_BSY_WIDTH 1
@@ -1738,6 +812,11 @@ static struct efab_mac_operations ef1002_mac_operations = {
#define FCN_MAC_SPEED_LBN 0
#define FCN_MAC_SPEED_WIDTH 2
+/* 10Gig Xaui XGXS Default Values */
+#define XX_TXDRV_DEQ_DEFAULT 0xe /* deq=.6 */
+#define XX_TXDRV_DTX_DEFAULT 0x5 /* 1.25 */
+#define XX_SD_CTL_DRV_DEFAULT 0 /* 20mA */
+
/* GMAC registers */
#define FALCON_GMAC_REGBANK 0xe00
#define FALCON_GMAC_REGBANK_SIZE 0x200
@@ -1801,18 +880,45 @@ static struct efab_mac_operations ef1002_mac_operations = {
#define FCN_XM_RXEN_LBN 1
#define FCN_XM_RXEN_WIDTH 1
+/* XGMAC management interrupt mask register */
+#define FCN_XM_MGT_INT_MSK_REG_MAC_B0 0x5
+#define FCN_XM_MSK_PRMBLE_ERR_LBN 2
+#define FCN_XM_MSK_PRMBLE_ERR_WIDTH 1
+#define FCN_XM_MSK_RMTFLT_LBN 1
+#define FCN_XM_MSK_RMTFLT_WIDTH 1
+#define FCN_XM_MSK_LCLFLT_LBN 0
+#define FCN_XM_MSK_LCLFLT_WIDTH 1
+
+/* XGMAC flow control register */
+#define FCN_XM_FC_REG_MAC 0x7
+#define FCN_XM_PAUSE_TIME_LBN 16
+#define FCN_XM_PAUSE_TIME_WIDTH 16
+#define FCN_XM_DIS_FCNTL_LBN 0
+#define FCN_XM_DIS_FCNTL_WIDTH 1
+
/* XGMAC transmit parameter register */
#define FCN_XM_TX_PARAM_REG_MAC 0x0d
#define FCN_XM_TX_JUMBO_MODE_LBN 31
#define FCN_XM_TX_JUMBO_MODE_WIDTH 1
#define FCN_XM_MAX_TX_FRM_SIZE_LBN 16
#define FCN_XM_MAX_TX_FRM_SIZE_WIDTH 14
+#define FCN_XM_ACPT_ALL_MCAST_LBN 11
+#define FCN_XM_ACPT_ALL_MCAST_WIDTH 1
/* XGMAC receive parameter register */
#define FCN_XM_RX_PARAM_REG_MAC 0x0e
#define FCN_XM_MAX_RX_FRM_SIZE_LBN 0
#define FCN_XM_MAX_RX_FRM_SIZE_WIDTH 14
+/* XGMAC management interrupt status register */
+#define FCN_XM_MGT_INT_REG_MAC_B0 0x0f
+#define FCN_XM_PRMBLE_ERR 2
+#define FCN_XM_PRMBLE_WIDTH 1
+#define FCN_XM_RMTFLT_LBN 1
+#define FCN_XM_RMTFLT_WIDTH 1
+#define FCN_XM_LCLFLT_LBN 0
+#define FCN_XM_LCLFLT_WIDTH 1
+
/* XAUI XGXS core status register */
#define FCN_XX_ALIGN_DONE_LBN 20
#define FCN_XX_ALIGN_DONE_WIDTH 1
@@ -1823,10 +929,35 @@ static struct efab_mac_operations ef1002_mac_operations = {
#define FCN_XX_COMMA_DET_LBN 12
#define FCN_XX_COMMA_DET_WIDTH 4
#define FCN_XX_COMMA_DET_RESET 0xf
-
+#define FCN_XX_CHARERR_LBN 4
+#define FCN_XX_CHARERR_WIDTH 4
+#define FCN_XX_CHARERR_RESET 0xf
+#define FCN_XX_DISPERR_LBN 0
+#define FCN_XX_DISPERR_WIDTH 4
+#define FCN_XX_DISPERR_RESET 0xf
/* XGXS/XAUI powerdown/reset register */
#define FCN_XX_PWR_RST_REG_MAC 0x10
+#define FCN_XX_PWRDND_EN_LBN 15
+#define FCN_XX_PWRDND_EN_WIDTH 1
+#define FCN_XX_PWRDNC_EN_LBN 14
+#define FCN_XX_PWRDNC_EN_WIDTH 1
+#define FCN_XX_PWRDNB_EN_LBN 13
+#define FCN_XX_PWRDNB_EN_WIDTH 1
+#define FCN_XX_PWRDNA_EN_LBN 12
+#define FCN_XX_PWRDNA_EN_WIDTH 1
+#define FCN_XX_RSTPLLCD_EN_LBN 9
+#define FCN_XX_RSTPLLCD_EN_WIDTH 1
+#define FCN_XX_RSTPLLAB_EN_LBN 8
+#define FCN_XX_RSTPLLAB_EN_WIDTH 1
+#define FCN_XX_RESETD_EN_LBN 7
+#define FCN_XX_RESETD_EN_WIDTH 1
+#define FCN_XX_RESETC_EN_LBN 6
+#define FCN_XX_RESETC_EN_WIDTH 1
+#define FCN_XX_RESETB_EN_LBN 5
+#define FCN_XX_RESETB_EN_WIDTH 1
+#define FCN_XX_RESETA_EN_LBN 4
+#define FCN_XX_RESETA_EN_WIDTH 1
#define FCN_XX_RSTXGXSRX_EN_LBN 2
#define FCN_XX_RSTXGXSRX_EN_WIDTH 1
#define FCN_XX_RSTXGXSTX_EN_LBN 1
@@ -1834,8 +965,66 @@ static struct efab_mac_operations ef1002_mac_operations = {
#define FCN_XX_RST_XX_EN_LBN 0
#define FCN_XX_RST_XX_EN_WIDTH 1
+
+/* XGXS/XAUI powerdown/reset control register */
+#define FCN_XX_SD_CTL_REG_MAC 0x11
+#define FCN_XX_TERMADJ1_LBN 17
+#define FCN_XX_TERMADJ1_WIDTH 1
+#define FCN_XX_TERMADJ0_LBN 16
+#define FCN_XX_TERMADJ0_WIDTH 1
+#define FCN_XX_HIDRVD_LBN 15
+#define FCN_XX_HIDRVD_WIDTH 1
+#define FCN_XX_LODRVD_LBN 14
+#define FCN_XX_LODRVD_WIDTH 1
+#define FCN_XX_HIDRVC_LBN 13
+#define FCN_XX_HIDRVC_WIDTH 1
+#define FCN_XX_LODRVC_LBN 12
+#define FCN_XX_LODRVC_WIDTH 1
+#define FCN_XX_HIDRVB_LBN 11
+#define FCN_XX_HIDRVB_WIDTH 1
+#define FCN_XX_LODRVB_LBN 10
+#define FCN_XX_LODRVB_WIDTH 1
+#define FCN_XX_HIDRVA_LBN 9
+#define FCN_XX_HIDRVA_WIDTH 1
+#define FCN_XX_LODRVA_LBN 8
+#define FCN_XX_LODRVA_WIDTH 1
+#define FCN_XX_LPBKD_LBN 3
+#define FCN_XX_LPBKD_WIDTH 1
+#define FCN_XX_LPBKC_LBN 2
+#define FCN_XX_LPBKC_WIDTH 1
+#define FCN_XX_LPBKB_LBN 1
+#define FCN_XX_LPBKB_WIDTH 1
+#define FCN_XX_LPBKA_LBN 0
+#define FCN_XX_LPBKA_WIDTH 1
+
+#define FCN_XX_TXDRV_CTL_REG_MAC 0x12
+#define FCN_XX_DEQD_LBN 28
+#define FCN_XX_DEQD_WIDTH 4
+#define FCN_XX_DEQC_LBN 24
+#define FCN_XX_DEQC_WIDTH 4
+#define FCN_XX_DEQB_LBN 20
+#define FCN_XX_DEQB_WIDTH 4
+#define FCN_XX_DEQA_LBN 16
+#define FCN_XX_DEQA_WIDTH 4
+#define FCN_XX_DTXD_LBN 12
+#define FCN_XX_DTXD_WIDTH 4
+#define FCN_XX_DTXC_LBN 8
+#define FCN_XX_DTXC_WIDTH 4
+#define FCN_XX_DTXB_LBN 4
+#define FCN_XX_DTXB_WIDTH 4
+#define FCN_XX_DTXA_LBN 0
+#define FCN_XX_DTXA_WIDTH 4
+
+/* Receive filter table */
+#define FCN_RX_FILTER_TBL0 0xF00000
+
/* Receive descriptor pointer table */
-#define FCN_RX_DESC_PTR_TBL_KER 0x11800
+#define FCN_RX_DESC_PTR_TBL_KER_A1 0x11800
+#define FCN_RX_DESC_PTR_TBL_KER_B0 0xF40000
+#define FCN_RX_ISCSI_DDIG_EN_LBN 88
+#define FCN_RX_ISCSI_DDIG_EN_WIDTH 1
+#define FCN_RX_ISCSI_HDIG_EN_LBN 87
+#define FCN_RX_ISCSI_HDIG_EN_WIDTH 1
#define FCN_RX_DESCQ_BUF_BASE_ID_LBN 36
#define FCN_RX_DESCQ_BUF_BASE_ID_WIDTH 20
#define FCN_RX_DESCQ_EVQ_ID_LBN 24
@@ -1856,9 +1045,16 @@ static struct efab_mac_operations ef1002_mac_operations = {
#define FCN_RX_DESCQ_EN_WIDTH 1
/* Transmit descriptor pointer table */
-#define FCN_TX_DESC_PTR_TBL_KER 0x11900
+#define FCN_TX_DESC_PTR_TBL_KER_A1 0x11900
+#define FCN_TX_DESC_PTR_TBL_KER_B0 0xF50000
+#define FCN_TX_NON_IP_DROP_DIS_B0_LBN 91
+#define FCN_TX_NON_IP_DROP_DIS_B0_WIDTH 1
#define FCN_TX_DESCQ_EN_LBN 88
#define FCN_TX_DESCQ_EN_WIDTH 1
+#define FCN_TX_ISCSI_DDIG_EN_LBN 87
+#define FCN_TX_ISCSI_DDIG_EN_WIDTH 1
+#define FCN_TX_ISCSI_HDIG_EN_LBN 86
+#define FCN_TX_ISCSI_HDIG_EN_WIDTH 1
#define FCN_TX_DESCQ_BUF_BASE_ID_LBN 36
#define FCN_TX_DESCQ_BUF_BASE_ID_WIDTH 20
#define FCN_TX_DESCQ_EVQ_ID_LBN 24
@@ -1877,7 +1073,8 @@ static struct efab_mac_operations ef1002_mac_operations = {
#define FCN_TX_DESCQ_FLUSH_WIDTH 1
/* Event queue pointer */
-#define FCN_EVQ_PTR_TBL_KER 0x11a00
+#define FCN_EVQ_PTR_TBL_KER_A1 0x11a00
+#define FCN_EVQ_PTR_TBL_KER_B0 0xf60000
#define FCN_EVQ_EN_LBN 23
#define FCN_EVQ_EN_WIDTH 1
#define FCN_EVQ_SIZE_LBN 20
@@ -1892,16 +1089,22 @@ static struct efab_mac_operations ef1002_mac_operations = {
#define FCN_EVQ_BUF_BASE_ID_LBN 0
#define FCN_EVQ_BUF_BASE_ID_WIDTH 20
+/* RSS indirection table */
+#define FCN_RX_RSS_INDIR_TBL_B0 0xFB0000
+
/* Event queue read pointer */
-#define FCN_EVQ_RPTR_REG_KER 0x11b00
+#define FCN_EVQ_RPTR_REG_KER_A1 0x11b00
+#define FCN_EVQ_RPTR_REG_KER_B0 0xfa0000
#define FCN_EVQ_RPTR_LBN 0
#define FCN_EVQ_RPTR_WIDTH 14
-#define FCN_EVQ_RPTR_REG_KER_DWORD ( FCN_EVQ_RPTR_REG_KER + 0 )
+#define FCN_EVQ_RPTR_REG_KER_DWORD_A1 ( FCN_EVQ_RPTR_REG_KER_A1 + 0 )
+#define FCN_EVQ_RPTR_REG_KER_DWORD_B0 ( FCN_EVQ_RPTR_REG_KER_B0 + 0 )
#define FCN_EVQ_RPTR_DWORD_LBN 0
#define FCN_EVQ_RPTR_DWORD_WIDTH 14
/* Special buffer descriptors */
-#define FCN_BUF_FULL_TBL_KER 0x18000
+#define FCN_BUF_FULL_TBL_KER_A1 0x18000
+#define FCN_BUF_FULL_TBL_KER_B0 0x800000
#define FCN_IP_DAT_BUF_SIZE_LBN 50
#define FCN_IP_DAT_BUF_SIZE_WIDTH 1
#define FCN_IP_DAT_BUF_SIZE_8K 1
@@ -1914,13 +1117,11 @@ static struct efab_mac_operations ef1002_mac_operations = {
/** Offset of a GMAC register within Falcon */
#define FALCON_GMAC_REG( efab, mac_reg ) \
( FALCON_GMAC_REGBANK + \
- ( (efab)->port * FALCON_GMAC_REGBANK_SIZE ) + \
( (mac_reg) * FALCON_GMAC_REG_SIZE ) )
/** Offset of an XMAC register within Falcon */
#define FALCON_XMAC_REG( efab_port, mac_reg ) \
( FALCON_XMAC_REGBANK + \
- ( (efab_port)->port * FALCON_XMAC_REGBANK_SIZE ) + \
( (mac_reg) * FALCON_XMAC_REG_SIZE ) )
#define FCN_MAC_DATA_LBN 0
@@ -1962,10 +1163,22 @@ static struct efab_mac_operations ef1002_mac_operations = {
#define FCN_TX_EV_DESC_PTR_LBN 0
#define FCN_TX_EV_DESC_PTR_WIDTH 12
-/* Fixed special buffer numbers to use */
-#define FALCON_EVQ_ID 0
-#define FALCON_TXD_ID 1
-#define FALCON_RXD_ID 2
+/*******************************************************************************
+ *
+ *
+ * Low-level hardware access
+ *
+ *
+ *******************************************************************************/
+
+#define FCN_REVISION_REG(efab, reg) \
+ ( ( efab->pci_revision == FALCON_REV_B0 ) ? reg ## _B0 : reg ## _A1 )
+
+#define EFAB_SET_OWORD_FIELD_VER(efab, reg, field, val) \
+ if ( efab->pci_revision == FALCON_REV_B0 ) \
+ EFAB_SET_OWORD_FIELD ( reg, field ## _B0, val ); \
+ else \
+ EFAB_SET_OWORD_FIELD ( reg, field ## _A1, val );
#if FALCON_USE_IO_BAR
@@ -1995,8 +1208,9 @@ static inline uint32_t _falcon_readl ( struct efab_nic *efab,
* Write to a Falcon register
*
*/
-static inline void falcon_write ( struct efab_nic *efab, efab_oword_t *value,
- unsigned int reg ) {
+static inline void
+falcon_write ( struct efab_nic *efab, efab_oword_t *value, unsigned int reg )
+{
EFAB_REGDUMP ( "Writing register %x with " EFAB_OWORD_FMT "\n",
reg, EFAB_OWORD_VAL ( *value ) );
@@ -2004,6 +1218,7 @@ static inline void falcon_write ( struct efab_nic *efab, efab_oword_t *value,
_falcon_writel ( efab, value->u32[0], reg + 0 );
_falcon_writel ( efab, value->u32[1], reg + 4 );
_falcon_writel ( efab, value->u32[2], reg + 8 );
+ wmb();
_falcon_writel ( efab, value->u32[3], reg + 12 );
wmb();
}
@@ -2012,10 +1227,11 @@ static inline void falcon_write ( struct efab_nic *efab, efab_oword_t *value,
* Write to Falcon SRAM
*
*/
-static inline void falcon_write_sram ( struct efab_nic *efab,
- efab_qword_t *value,
- unsigned int index ) {
- unsigned int reg = ( FCN_BUF_FULL_TBL_KER +
+static inline void
+falcon_write_sram ( struct efab_nic *efab, efab_qword_t *value,
+ unsigned int index )
+{
+ unsigned int reg = ( FCN_REVISION_REG ( efab, FCN_BUF_FULL_TBL_KER ) +
( index * sizeof ( *value ) ) );
EFAB_REGDUMP ( "Writing SRAM register %x with " EFAB_QWORD_FMT "\n",
@@ -2030,8 +1246,9 @@ static inline void falcon_write_sram ( struct efab_nic *efab,
* Write dword to Falcon register that allows partial writes
*
*/
-static inline void falcon_writel ( struct efab_nic *efab, efab_dword_t *value,
- unsigned int reg ) {
+static inline void
+falcon_writel ( struct efab_nic *efab, efab_dword_t *value, unsigned int reg )
+{
EFAB_REGDUMP ( "Writing partial register %x with " EFAB_DWORD_FMT "\n",
reg, EFAB_DWORD_VAL ( *value ) );
_falcon_writel ( efab, value->u32[0], reg );
@@ -2041,9 +1258,11 @@ static inline void falcon_writel ( struct efab_nic *efab, efab_dword_t *value,
* Read from a Falcon register
*
*/
-static inline void falcon_read ( struct efab_nic *efab, efab_oword_t *value,
- unsigned int reg ) {
+static inline void
+falcon_read ( struct efab_nic *efab, efab_oword_t *value, unsigned int reg )
+{
value->u32[0] = _falcon_readl ( efab, reg + 0 );
+ wmb();
value->u32[1] = _falcon_readl ( efab, reg + 4 );
value->u32[2] = _falcon_readl ( efab, reg + 8 );
value->u32[3] = _falcon_readl ( efab, reg + 12 );
@@ -2056,10 +1275,11 @@ static inline void falcon_read ( struct efab_nic *efab, efab_oword_t *value,
* Read from Falcon SRAM
*
*/
-static inline void falcon_read_sram ( struct efab_nic *efab,
- efab_qword_t *value,
- unsigned int index ) {
- unsigned int reg = ( FCN_BUF_FULL_TBL_KER +
+static inline void
+falcon_read_sram ( struct efab_nic *efab, efab_qword_t *value,
+ unsigned int index )
+{
+ unsigned int reg = ( FCN_REVISION_REG ( efab, FCN_BUF_FULL_TBL_KER ) +
( index * sizeof ( *value ) ) );
value->u32[0] = _falcon_readl ( efab, reg + 0 );
@@ -2072,44 +1292,14 @@ static inline void falcon_read_sram ( struct efab_nic *efab,
* Read dword from a portion of a Falcon register
*
*/
-static inline void falcon_readl ( struct efab_nic *efab, efab_dword_t *value,
- unsigned int reg ) {
+static inline void
+falcon_readl ( struct efab_nic *efab, efab_dword_t *value, unsigned int reg )
+{
value->u32[0] = _falcon_readl ( efab, reg );
EFAB_REGDUMP ( "Read from register %x, got " EFAB_DWORD_FMT "\n",
reg, EFAB_DWORD_VAL ( *value ) );
}
-/**
- * Verified write to Falcon SRAM
- *
- */
-static inline void falcon_write_sram_verify ( struct efab_nic *efab,
- efab_qword_t *value,
- unsigned int index ) {
- efab_qword_t verify;
-
- falcon_write_sram ( efab, value, index );
- udelay ( 1000 );
- falcon_read_sram ( efab, &verify, index );
- if ( memcmp ( &verify, value, sizeof ( verify ) ) != 0 ) {
- EFAB_ERR ( "SRAM index %x failure: wrote " EFAB_QWORD_FMT
- " got " EFAB_QWORD_FMT "\n", index,
- EFAB_QWORD_VAL ( *value ),
- EFAB_QWORD_VAL ( verify ) );
- }
-}
-
-/**
- * Get memory base
- *
- */
-static void falcon_get_membase ( struct efab_nic *efab ) {
- unsigned long membase_phys;
-
- membase_phys = pci_bar_start ( efab->pci, PCI_BASE_ADDRESS_2 );
- efab->membase = ioremap ( membase_phys, 0x20000 );
-}
-
#define FCN_DUMP_REG( efab, _reg ) do { \
efab_oword_t reg; \
falcon_read ( efab, &reg, _reg ); \
@@ -2125,12 +1315,47 @@ static void falcon_get_membase ( struct efab_nic *efab ) {
} while ( 0 );
/**
+ * See if an event is present
+ *
+ * @v event Falcon event structure
+ * @ret True An event is pending
+ * @ret False No event is pending
+ *
+ * We check both the high and low dword of the event for all ones. We
+ * wrote all ones when we cleared the event, and no valid event can
+ * have all ones in either its high or low dwords. This approach is
+ * robust against reordering.
+ *
+ * Note that using a single 64-bit comparison is incorrect; even
+ * though the CPU read will be atomic, the DMA write may not be.
+ */
+static inline int
+falcon_event_present ( falcon_event_t* event )
+{
+ return ( ! ( EFAB_DWORD_IS_ALL_ONES ( event->dword[0] ) |
+ EFAB_DWORD_IS_ALL_ONES ( event->dword[1] ) ) );
+}
+
+static void
+falcon_eventq_read_ack ( struct efab_nic *efab, struct efab_ev_queue *ev_queue )
+{
+ efab_dword_t reg;
+
+ EFAB_POPULATE_DWORD_1 ( reg, FCN_EVQ_RPTR_DWORD, ev_queue->read_ptr );
+ falcon_writel ( efab, &reg,
+ FCN_REVISION_REG ( efab, FCN_EVQ_RPTR_REG_KER_DWORD ) );
+}
+
+#if 0
+/**
* Dump register contents (for debugging)
*
* Marked as static inline so that it will not be compiled in if not
* used.
*/
-static inline void falcon_dump_regs ( struct efab_nic *efab ) {
+static inline void
+falcon_dump_regs ( struct efab_nic *efab )
+{
FCN_DUMP_REG ( efab, FCN_INT_EN_REG_KER );
FCN_DUMP_REG ( efab, FCN_INT_ADR_REG_KER );
FCN_DUMP_REG ( efab, FCN_GLB_CTL_REG_KER );
@@ -2142,9 +1367,9 @@ static inline void falcon_dump_regs ( struct efab_nic *efab ) {
FCN_DUMP_REG ( efab, FCN_TX_DC_CFG_REG_KER );
FCN_DUMP_REG ( efab, FCN_MAC0_CTRL_REG_KER );
FCN_DUMP_REG ( efab, FCN_MAC1_CTRL_REG_KER );
- FCN_DUMP_REG ( efab, FCN_RX_DESC_PTR_TBL_KER );
- FCN_DUMP_REG ( efab, FCN_TX_DESC_PTR_TBL_KER );
- FCN_DUMP_REG ( efab, FCN_EVQ_PTR_TBL_KER );
+ FCN_DUMP_REG ( efab, FCN_REVISION_REG ( efab, FCN_RX_DESC_PTR_TBL_KER ) );
+ FCN_DUMP_REG ( efab, FCN_REVISION_REG ( efab, FCN_TX_DESC_PTR_TBL_KER ) );
+ FCN_DUMP_REG ( efab, FCN_REVISION_REG ( efab, FCN_EVQ_PTR_TBL_KER ) );
FCN_DUMP_MAC_REG ( efab, GM_CFG1_REG_MAC );
FCN_DUMP_MAC_REG ( efab, GM_CFG2_REG_MAC );
FCN_DUMP_MAC_REG ( efab, GM_MAX_FLEN_REG_MAC );
@@ -2158,391 +1383,356 @@ static inline void falcon_dump_regs ( struct efab_nic *efab ) {
FCN_DUMP_MAC_REG ( efab, GMF_CFG4_REG_MAC );
FCN_DUMP_MAC_REG ( efab, GMF_CFG5_REG_MAC );
}
+#endif
-/**
- * Create special buffer
- *
- */
-static void falcon_create_special_buffer ( struct efab_nic *efab,
- void *addr, unsigned int index ) {
- efab_qword_t buf_desc;
- unsigned long dma_addr;
+static void
+falcon_interrupts ( struct efab_nic *efab, int enabled, int force )
+{
+ efab_oword_t int_en_reg_ker;
- memset ( addr, 0, 4096 );
- dma_addr = virt_to_bus ( addr );
- EFAB_ASSERT ( ( dma_addr & ( EFAB_BUF_ALIGN - 1 ) ) == 0 );
- EFAB_POPULATE_QWORD_3 ( buf_desc,
- FCN_IP_DAT_BUF_SIZE, FCN_IP_DAT_BUF_SIZE_4K,
- FCN_BUF_ADR_FBUF, ( dma_addr >> 12 ),
- FCN_BUF_OWNER_ID_FBUF, 0 );
- falcon_write_sram_verify ( efab, &buf_desc, index );
+ EFAB_POPULATE_OWORD_2 ( int_en_reg_ker,
+ FCN_KER_INT_KER, force,
+ FCN_DRV_INT_EN_KER, enabled );
+ falcon_write ( efab, &int_en_reg_ker, FCN_INT_EN_REG_KER );
}
-/**
- * Update event queue read pointer
+/*******************************************************************************
*
- */
-static void falcon_eventq_read_ack ( struct efab_nic *efab ) {
- efab_dword_t reg;
-
- EFAB_ASSERT ( efab->eventq_read_ptr < EFAB_EVQ_SIZE );
-
- EFAB_POPULATE_DWORD_1 ( reg, FCN_EVQ_RPTR_DWORD,
- efab->eventq_read_ptr );
- falcon_writel ( efab, &reg, FCN_EVQ_RPTR_REG_KER_DWORD );
-}
-
-/**
- * Reset device
*
- */
-static int falcon_reset ( struct efab_nic *efab ) {
- efab_oword_t glb_ctl_reg_ker;
-
- /* Initiate software reset */
- EFAB_POPULATE_OWORD_7 ( glb_ctl_reg_ker,
- PCIE_CORE_RST_CTL, EXCLUDE_FROM_RESET,
- PCIE_NSTCK_RST_CTL, EXCLUDE_FROM_RESET,
- PCIE_SD_RST_CTL, EXCLUDE_FROM_RESET,
- EE_RST_CTL, EXCLUDE_FROM_RESET,
- PCIX_RST_CTL, EXCLUDE_FROM_RESET,
- EXT_PHY_RST_DUR, 0x7 /* datasheet recommended */,
- SWRST, 1 );
-
- falcon_write ( efab, &glb_ctl_reg_ker, FCN_GLB_CTL_REG_KER );
-
- /* Allow 20ms for reset */
- mdelay ( 20 );
+ * SPI access
+ *
+ *
+ *******************************************************************************/
- /* Check for device reset complete */
- falcon_read ( efab, &glb_ctl_reg_ker, FCN_GLB_CTL_REG_KER );
- if ( EFAB_OWORD_FIELD ( glb_ctl_reg_ker, SWRST ) != 0 ) {
- EFAB_ERR ( "Reset failed\n" );
- return 0;
- }
- return 1;
-}
+/** Maximum length for a single SPI transaction */
+#define FALCON_SPI_MAX_LEN 16
-/**
- * Wait for SPI command completion
- *
- */
-static int falcon_spi_wait ( struct efab_nic *efab ) {
+static int
+falcon_spi_wait ( struct efab_nic *efab )
+{
efab_oword_t reg;
int count;
count = 0;
do {
udelay ( 100 );
- falcon_read ( efab, &reg, FCN_EE_SPI_HCMD_REG_KER );
+ falcon_read ( efab, &reg, FCN_EE_SPI_HCMD_REG );
if ( EFAB_OWORD_FIELD ( reg, FCN_EE_SPI_HCMD_CMD_EN ) == 0 )
- return 1;
+ return 0;
} while ( ++count < 1000 );
- printf ( "Timed out waiting for SPI\n" );
- return 0;
+
+ EFAB_ERR ( "Timed out waiting for SPI\n" );
+ return -ETIMEDOUT;
}
-/**
- * Perform SPI read/write
- *
- */
-static int falcon_spi_rw ( struct spi_bus *bus, struct spi_device *device,
- unsigned int command, int address,
- const void *data_out, void *data_in, size_t len ) {
- struct efab_nic *efab = container_of ( bus, struct efab_nic, spi );
+static int
+falcon_spi_rw ( struct spi_bus* bus, struct spi_device *device,
+ unsigned int command, int address,
+ const void* data_out, void *data_in, size_t len )
+{
+ struct efab_nic *efab = container_of ( bus, struct efab_nic, spi_bus );
+ int address_len, rc, device_id, read_cmd;
efab_oword_t reg;
- /* Program address register */
- EFAB_POPULATE_OWORD_1 ( reg, FCN_EE_SPI_HADR_ADR, address );
- falcon_write ( efab, &reg, FCN_EE_SPI_HADR_REG_KER );
-
- /* Program data register, if applicable */
+ /* falcon_init_spi_device() should have reduced the block size
+ * down so this constraint holds */
+ assert ( len <= FALCON_SPI_MAX_LEN );
+
+ /* Is this the FLASH or EEPROM device? */
+ if ( device == &efab->spi_flash )
+ device_id = FCN_EE_SPI_FLASH;
+ else if ( device == &efab->spi_eeprom )
+ device_id = FCN_EE_SPI_EEPROM;
+ else {
+ EFAB_ERR ( "Unknown device %p\n", device );
+ return -EINVAL;
+ }
+
+ EFAB_TRACE ( "Executing spi command %d on device %d at %d for %d bytes\n",
+ command, device_id, address, len );
+
+ /* The bus must be idle */
+ rc = falcon_spi_wait ( efab );
+ if ( rc )
+ goto fail1;
+
+ /* Copy data out */
if ( data_out ) {
memcpy ( &reg, data_out, len );
- falcon_write ( efab, &reg, FCN_EE_SPI_HDATA_REG_KER );
+ falcon_write ( efab, &reg, FCN_EE_SPI_HDATA_REG );
+ }
+
+ /* Program address register */
+ if ( address >= 0 ) {
+ EFAB_POPULATE_OWORD_1 ( reg, FCN_EE_SPI_HADR_ADR, address );
+ falcon_write ( efab, &reg, FCN_EE_SPI_HADR_REG );
}
/* Issue command */
+ address_len = ( address >= 0 ) ? device->address_len / 8 : 0;
+ read_cmd = ( data_in ? FCN_EE_SPI_READ : FCN_EE_SPI_WRITE );
EFAB_POPULATE_OWORD_7 ( reg,
- FCN_EE_SPI_HCMD_CMD_EN, 1,
- FCN_EE_SPI_HCMD_SF_SEL, device->slave,
+ FCN_EE_SPI_HCMD_CMD_EN, 1,
+ FCN_EE_SPI_HCMD_SF_SEL, device_id,
FCN_EE_SPI_HCMD_DABCNT, len,
- FCN_EE_SPI_HCMD_READ, ( data_out ?
- FCN_EE_SPI_WRITE : FCN_EE_SPI_READ ),
+ FCN_EE_SPI_HCMD_READ, read_cmd,
FCN_EE_SPI_HCMD_DUBCNT, 0,
- FCN_EE_SPI_HCMD_ADBCNT,
- ( device->address_len / 8 ),
+ FCN_EE_SPI_HCMD_ADBCNT, address_len,
FCN_EE_SPI_HCMD_ENC, command );
- falcon_write ( efab, &reg, FCN_EE_SPI_HCMD_REG_KER );
-
- /* Wait for operation to complete */
- if ( ! falcon_spi_wait ( efab ) )
- return 0;
+ falcon_write ( efab, &reg, FCN_EE_SPI_HCMD_REG );
- /* Read data, if applicable */
+ /* Wait for the command to complete */
+ rc = falcon_spi_wait ( efab );
+ if ( rc )
+ goto fail2;
+
+ /* Copy data in */
if ( data_in ) {
- falcon_read ( efab, &reg, FCN_EE_SPI_HDATA_REG_KER );
+ falcon_read ( efab, &reg, FCN_EE_SPI_HDATA_REG );
memcpy ( data_in, &reg, len );
}
-
+
return 0;
-}
-/**
- * Initialise SPI bus and devices
- *
- */
-static void falcon_init_spi ( struct efab_nic *efab ) {
- efab_oword_t reg;
- int eeprom_9bit;
-
- /* Initialise SPI bus */
- efab->spi.rw = falcon_spi_rw;
- efab->falcon_eeprom.bus = &efab->spi;
- efab->falcon_eeprom.slave = FCN_EE_SPI_EEPROM;
- efab->falcon_flash.bus = &efab->spi;
- efab->falcon_flash.slave = FCN_EE_SPI_FLASH;
-
- /* Initialise flash if present */
- if ( efab->has_flash ) {
- DBG ( "Flash is present\n" );
- init_at25f1024 ( &efab->falcon_flash );
- }
-
- /* Initialise EEPROM if present */
- if ( efab->has_eeprom ) {
- if ( efab->is_asic ) {
- falcon_read ( efab, &reg, FCN_VPD_CONFIG_REG_KER );
- eeprom_9bit = EFAB_OWORD_FIELD ( reg, FCN_VPD_9BIT );
- } else {
- eeprom_9bit = 1;
- }
- if ( eeprom_9bit ) {
- DBG ( "Small EEPROM is present\n" );
- init_at25040 ( &efab->falcon_eeprom );
- } else {
- DBG ( "Large EEPROM is present\n" );
- init_mc25xx640 ( &efab->falcon_eeprom );
- /* Falcon's SPI interface cannot support a block
- size larger than 16, so forcibly reduce it
- */
- efab->falcon_eeprom.nvs.block_size = 16;
- }
- }
-}
+fail2:
+fail1:
+ EFAB_ERR ( "Failed SPI command %d to device %d address 0x%x len 0x%x\n",
+ command, device_id, address, len );
-/** Offset of MAC address within EEPROM or Flash */
-#define FALCON_MAC_ADDRESS_OFFSET(port) ( 0x310 + 0x08 * (port) )
+ return rc;
+}
-static struct nvo_fragment falcon_eeprom_fragments[] = {
- { 0x100, 0x100 },
+/** Portion of EEPROM available for non-volatile options */
+static struct nvo_fragment falcon_nvo_fragments[] = {
+ { 0x100, 0xf0 },
{ 0, 0 }
};
-/**
- * Read MAC address from EEPROM
+/*******************************************************************************
*
- */
-static int falcon_read_eeprom ( struct efab_nic *efab ) {
- struct nvs_device *nvs;
-
- /* Determine the NVS device containing the MAC address */
- nvs = ( efab->has_flash ?
- &efab->falcon_flash.nvs : &efab->falcon_eeprom.nvs );
-
- return ( nvs_read ( nvs, FALCON_MAC_ADDRESS_OFFSET ( efab->port ),
- efab->mac_addr, sizeof ( efab->mac_addr ) ) == 0 );
-}
-
-/** RX descriptor */
-typedef efab_qword_t falcon_rx_desc_t;
-
-/**
- * Build RX descriptor
*
- */
-static void falcon_build_rx_desc ( struct efab_nic *efab,
- struct efab_rx_buf *rx_buf ) {
- falcon_rx_desc_t *rxd;
-
- rxd = ( ( falcon_rx_desc_t * ) efab->rxd ) + rx_buf->id;
- EFAB_POPULATE_QWORD_2 ( *rxd,
- FCN_RX_KER_BUF_SIZE, EFAB_DATA_BUF_SIZE,
- FCN_RX_KER_BUF_ADR,
- virt_to_bus ( rx_buf->addr ) );
-}
-
-/**
- * Update RX descriptor write pointer
+ * Falcon bit-bashed I2C interface
*
- */
-static void falcon_notify_rx_desc ( struct efab_nic *efab ) {
- efab_dword_t reg;
-
- EFAB_POPULATE_DWORD_1 ( reg, FCN_RX_DESC_WPTR_DWORD,
- efab->rx_write_ptr );
- falcon_writel ( efab, &reg, FCN_RX_DESC_UPD_REG_KER_DWORD );
-}
+ *
+ *******************************************************************************/
-/** TX descriptor */
-typedef efab_qword_t falcon_tx_desc_t;
+static void
+falcon_i2c_bit_write ( struct bit_basher *basher, unsigned int bit_id,
+ unsigned long data )
+{
+ struct efab_nic *efab = container_of ( basher, struct efab_nic,
+ i2c_bb.basher );
+ efab_oword_t reg;
-/**
- * Build TX descriptor
- *
- */
-static void falcon_build_tx_desc ( struct efab_nic *efab,
- struct efab_tx_buf *tx_buf ) {
- falcon_rx_desc_t *txd;
+ falcon_read ( efab, &reg, FCN_GPIO_CTL_REG_KER );
+ switch ( bit_id ) {
+ case I2C_BIT_SCL:
+ EFAB_SET_OWORD_FIELD ( reg, FCN_GPIO0_OEN, ( data ? 0 : 1 ) );
+ break;
+ case I2C_BIT_SDA:
+ EFAB_SET_OWORD_FIELD ( reg, FCN_GPIO3_OEN, ( data ? 0 : 1 ) );
+ break;
+ default:
+ EFAB_ERR ( "%s bit=%d\n", __func__, bit_id );
+ break;
+ }
- txd = ( ( falcon_rx_desc_t * ) efab->txd ) + tx_buf->id;
- EFAB_POPULATE_QWORD_3 ( *txd,
- FCN_TX_KER_PORT, efab->port,
- FCN_TX_KER_BYTE_CNT, tx_buf->len,
- FCN_TX_KER_BUF_ADR,
- virt_to_bus ( tx_buf->addr ) );
+ falcon_write ( efab, &reg, FCN_GPIO_CTL_REG_KER );
}
-/**
- * Update TX descriptor write pointer
- *
- */
-static void falcon_notify_tx_desc ( struct efab_nic *efab ) {
- efab_dword_t reg;
+static int
+falcon_i2c_bit_read ( struct bit_basher *basher, unsigned int bit_id )
+{
+ struct efab_nic *efab = container_of ( basher, struct efab_nic,
+ i2c_bb.basher );
+ efab_oword_t reg;
+
+ falcon_read ( efab, &reg, FCN_GPIO_CTL_REG_KER );
+ switch ( bit_id ) {
+ case I2C_BIT_SCL:
+ return EFAB_OWORD_FIELD ( reg, FCN_GPIO0_IN );
+ break;
+ case I2C_BIT_SDA:
+ return EFAB_OWORD_FIELD ( reg, FCN_GPIO3_IN );
+ break;
+ default:
+ EFAB_ERR ( "%s bit=%d\n", __func__, bit_id );
+ break;
+ }
- EFAB_POPULATE_DWORD_1 ( reg, FCN_TX_DESC_WPTR_DWORD,
- efab->tx_write_ptr );
- falcon_writel ( efab, &reg, FCN_TX_DESC_UPD_REG_KER_DWORD );
+ return -1;
}
-/** An event */
-typedef efab_qword_t falcon_event_t;
+static struct bit_basher_operations falcon_i2c_bit_ops = {
+ .read = falcon_i2c_bit_read,
+ .write = falcon_i2c_bit_write,
+};
-/**
- * See if an event is present
+
+/*******************************************************************************
*
- * @v event Falcon event structure
- * @ret True An event is pending
- * @ret False No event is pending
*
- * We check both the high and low dword of the event for all ones. We
- * wrote all ones when we cleared the event, and no valid event can
- * have all ones in either its high or low dwords. This approach is
- * robust against reordering.
+ * MDIO access
*
- * Note that using a single 64-bit comparison is incorrect; even
- * though the CPU read will be atomic, the DMA write may not be.
- */
-static inline int falcon_event_present ( falcon_event_t* event ) {
- return ( ! ( EFAB_DWORD_IS_ALL_ONES ( event->dword[0] ) |
- EFAB_DWORD_IS_ALL_ONES ( event->dword[1] ) ) );
-}
-
-/**
- * Retrieve event from event queue
*
- */
-static int falcon_fetch_event ( struct efab_nic *efab,
- struct efab_event *event ) {
- falcon_event_t *evt;
- int ev_code;
- int rx_port;
+ *******************************************************************************/
- /* Check for event */
- evt = ( ( falcon_event_t * ) efab->eventq ) + efab->eventq_read_ptr;
- if ( !falcon_event_present ( evt ) ) {
- /* No event */
- return 0;
- }
-
- DBG ( "Event is " EFAB_QWORD_FMT "\n", EFAB_QWORD_VAL ( *evt ) );
+static int
+falcon_gmii_wait ( struct efab_nic *efab )
+{
+ efab_dword_t md_stat;
+ int count;
- /* Decode event */
- ev_code = EFAB_QWORD_FIELD ( *evt, FCN_EV_CODE );
- event->drop = 0;
- switch ( ev_code ) {
- case FCN_TX_IP_EV_DECODE:
- event->type = EFAB_EV_TX;
- break;
- case FCN_RX_IP_EV_DECODE:
- event->type = EFAB_EV_RX;
- event->rx_id = EFAB_QWORD_FIELD ( *evt, FCN_RX_EV_DESC_PTR );
- event->rx_len = EFAB_QWORD_FIELD ( *evt, FCN_RX_EV_BYTE_CNT );
- event->drop = !EFAB_QWORD_FIELD ( *evt, FCN_RX_EV_PKT_OK );
- rx_port = EFAB_QWORD_FIELD ( *evt, FCN_RX_PORT );
- if ( rx_port != efab->port ) {
- /* Ignore packets on the wrong port. We can't
- * just set event->type = EFAB_EV_NONE,
- * because then the descriptor ring won't get
- * refilled.
- */
- event->rx_len = 0;
+ /* wait upto 10ms */
+ for (count = 0; count < 1000; count++) {
+ falcon_readl ( efab, &md_stat, FCN_MD_STAT_REG_KER );
+ if ( EFAB_DWORD_FIELD ( md_stat, FCN_MD_BSY ) == 0 ) {
+ if ( EFAB_DWORD_FIELD ( md_stat, FCN_MD_LNFL ) != 0 ||
+ EFAB_DWORD_FIELD ( md_stat, FCN_MD_BSERR ) != 0 ) {
+ EFAB_ERR ( "Error from GMII access "
+ EFAB_DWORD_FMT"\n",
+ EFAB_DWORD_VAL ( md_stat ));
+ return -EIO;
+ }
+ return 0;
}
- break;
- case FCN_DRIVER_EV_DECODE:
- /* Ignore start-of-day events */
- event->type = EFAB_EV_NONE;
- break;
- default:
- EFAB_ERR ( "Unknown event type %d data %08lx\n", ev_code,
- EFAB_DWORD_FIELD ( *evt, EFAB_DWORD_0 ) );
- event->type = EFAB_EV_NONE;
+ udelay(10);
}
- /* Clear event and any pending interrupts */
- EFAB_SET_QWORD ( *evt );
- falcon_writel ( efab, 0, FCN_INT_ACK_KER_REG );
- udelay ( 10 );
+ EFAB_ERR ( "Timed out waiting for GMII\n" );
+ return -ETIMEDOUT;
+}
- /* Increment and update event queue read pointer */
- efab->eventq_read_ptr = ( ( efab->eventq_read_ptr + 1 )
- % EFAB_EVQ_SIZE );
- falcon_eventq_read_ack ( efab );
+static void
+falcon_mdio_write ( struct efab_nic *efab, int device,
+ int location, int value )
+{
+ efab_oword_t reg;
- return 1;
-}
+ EFAB_TRACE ( "Writing GMII %d register %02x with %04x\n",
+ device, location, value );
-/**
- * Enable/disable/generate interrupt
- *
- */
-static inline void falcon_interrupts ( struct efab_nic *efab, int enabled,
- int force ) {
- efab_oword_t int_en_reg_ker;
+ /* Check MII not currently being accessed */
+ if ( falcon_gmii_wait ( efab ) )
+ return;
- EFAB_POPULATE_OWORD_2 ( int_en_reg_ker,
- FCN_KER_INT_KER, force,
- FCN_DRV_INT_EN_KER, enabled );
- falcon_write ( efab, &int_en_reg_ker, FCN_INT_EN_REG_KER );
-}
+ /* Write the address/ID register */
+ EFAB_POPULATE_OWORD_1 ( reg, FCN_MD_PHY_ADR, location );
+ falcon_write ( efab, &reg, FCN_MD_PHY_ADR_REG_KER );
-/**
- * Enable/disable interrupts
- *
- */
-static void falcon_mask_irq ( struct efab_nic *efab, int enabled ) {
- falcon_interrupts ( efab, enabled, 0 );
- if ( enabled ) {
- /* Events won't trigger interrupts until we do this */
- falcon_eventq_read_ack ( efab );
+ if ( efab->phy_10g ) {
+ /* clause45 */
+ EFAB_POPULATE_OWORD_2 ( reg,
+ FCN_MD_PRT_ADR, efab->phy_addr,
+ FCN_MD_DEV_ADR, device );
}
-}
+ else {
+ /* clause22 */
+ assert ( device == 0 );
-/**
- * Generate interrupt
- *
- */
-static void falcon_generate_irq ( struct efab_nic *efab ) {
- falcon_interrupts ( efab, 1, 1 );
+ EFAB_POPULATE_OWORD_2 ( reg,
+ FCN_MD_PRT_ADR, efab->phy_addr,
+ FCN_MD_DEV_ADR, location );
+ }
+ falcon_write ( efab, &reg, FCN_MD_ID_REG_KER );
+
+
+ /* Write data */
+ EFAB_POPULATE_OWORD_1 ( reg, FCN_MD_TXD, value );
+ falcon_write ( efab, &reg, FCN_MD_TXD_REG_KER );
+
+ EFAB_POPULATE_OWORD_2 ( reg,
+ FCN_MD_WRC, 1,
+ FCN_MD_GC, ( efab->phy_10g ? 0 : 1 ) );
+ falcon_write ( efab, &reg, FCN_MD_CS_REG_KER );
+
+ /* Wait for data to be written */
+ if ( falcon_gmii_wait ( efab ) ) {
+ /* Abort the write operation */
+ EFAB_POPULATE_OWORD_2 ( reg,
+ FCN_MD_WRC, 0,
+ FCN_MD_GC, 1);
+ falcon_write ( efab, &reg, FCN_MD_CS_REG_KER );
+ udelay(10);
+ }
}
+static int
+falcon_mdio_read ( struct efab_nic *efab, int device, int location )
+{
+ efab_oword_t reg;
+ int value;
-/**
- * Reconfigure MAC wrapper
+ /* Check MII not currently being accessed */
+ if ( falcon_gmii_wait ( efab ) )
+ return -1;
+
+ if ( efab->phy_10g ) {
+ /* clause45 */
+ EFAB_POPULATE_OWORD_1 ( reg, FCN_MD_PHY_ADR, location );
+ falcon_write ( efab, &reg, FCN_MD_PHY_ADR_REG_KER );
+
+ EFAB_POPULATE_OWORD_2 ( reg,
+ FCN_MD_PRT_ADR, efab->phy_addr,
+ FCN_MD_DEV_ADR, device );
+ falcon_write ( efab, &reg, FCN_MD_ID_REG_KER);
+
+ /* request data to be read */
+ EFAB_POPULATE_OWORD_2 ( reg,
+ FCN_MD_RDC, 1,
+ FCN_MD_GC, 0 );
+ }
+ else {
+ /* clause22 */
+ assert ( device == 0 );
+
+ EFAB_POPULATE_OWORD_2 ( reg,
+ FCN_MD_PRT_ADR, efab->phy_addr,
+ FCN_MD_DEV_ADR, location );
+ falcon_write ( efab, &reg, FCN_MD_ID_REG_KER );
+
+ /* Request data to be read */
+ EFAB_POPULATE_OWORD_2 ( reg,
+ FCN_MD_RIC, 1,
+ FCN_MD_GC, 1 );
+ }
+
+ falcon_write ( efab, &reg, FCN_MD_CS_REG_KER );
+
+ /* Wait for data to become available */
+ if ( falcon_gmii_wait ( efab ) ) {
+ /* Abort the read operation */
+ EFAB_POPULATE_OWORD_2 ( reg,
+ FCN_MD_RIC, 0,
+ FCN_MD_GC, 1 );
+ falcon_write ( efab, &reg, FCN_MD_CS_REG_KER );
+ udelay ( 10 );
+ value = -1;
+ }
+ else {
+ /* Read the data */
+ falcon_read ( efab, &reg, FCN_MD_RXD_REG_KER );
+ value = EFAB_OWORD_FIELD ( reg, FCN_MD_RXD );
+ }
+
+ EFAB_TRACE ( "Read from GMII %d register %02x, got %04x\n",
+ device, location, value );
+
+ return value;
+}
+
+/*******************************************************************************
*
- */
-static void falcon_reconfigure_mac_wrapper ( struct efab_nic *efab ) {
+ *
+ * MAC wrapper
+ *
+ *
+ *******************************************************************************/
+
+static void
+falcon_reconfigure_mac_wrapper ( struct efab_nic *efab )
+{
efab_oword_t reg;
int link_speed;
@@ -2561,22 +1751,153 @@ static void falcon_reconfigure_mac_wrapper ( struct efab_nic *efab ) {
FCN_MAC_UC_PROM, 0,
FCN_MAC_LINK_STATUS, 1,
FCN_MAC_SPEED, link_speed );
- falcon_write ( efab, &reg,
- ( efab->port == 0 ?
- FCN_MAC0_CTRL_REG_KER : FCN_MAC1_CTRL_REG_KER ) );
- /* Disable flow-control (i.e. never generate pause frames) */
- falcon_read ( efab, &reg, FCN_RX_CFG_REG_KER );
- EFAB_SET_OWORD_FIELD ( reg, FCN_RX_XOFF_EN, 0 );
- falcon_write ( efab, &reg, FCN_RX_CFG_REG_KER );
+ falcon_write ( efab, &reg, FCN_MAC0_CTRL_REG_KER );
}
-/**
- * Write dword to a Falcon MAC register
+/*******************************************************************************
*
- */
-static void falcon_gmac_writel ( struct efab_nic *efab,
- efab_dword_t *value, unsigned int mac_reg ) {
+ *
+ * GMAC handling
+ *
+ *
+ *******************************************************************************/
+
+/* GMAC configuration register 1 */
+#define GM_CFG1_REG_MAC 0x00
+#define GM_SW_RST_LBN 31
+#define GM_SW_RST_WIDTH 1
+#define GM_RX_FC_EN_LBN 5
+#define GM_RX_FC_EN_WIDTH 1
+#define GM_TX_FC_EN_LBN 4
+#define GM_TX_FC_EN_WIDTH 1
+#define GM_RX_EN_LBN 2
+#define GM_RX_EN_WIDTH 1
+#define GM_TX_EN_LBN 0
+#define GM_TX_EN_WIDTH 1
+
+/* GMAC configuration register 2 */
+#define GM_CFG2_REG_MAC 0x01
+#define GM_PAMBL_LEN_LBN 12
+#define GM_PAMBL_LEN_WIDTH 4
+#define GM_IF_MODE_LBN 8
+#define GM_IF_MODE_WIDTH 2
+#define GM_PAD_CRC_EN_LBN 2
+#define GM_PAD_CRC_EN_WIDTH 1
+#define GM_FD_LBN 0
+#define GM_FD_WIDTH 1
+
+/* GMAC maximum frame length register */
+#define GM_MAX_FLEN_REG_MAC 0x04
+#define GM_MAX_FLEN_LBN 0
+#define GM_MAX_FLEN_WIDTH 16
+
+/* GMAC MII management configuration register */
+#define GM_MII_MGMT_CFG_REG_MAC 0x08
+#define GM_MGMT_CLK_SEL_LBN 0
+#define GM_MGMT_CLK_SEL_WIDTH 3
+
+/* GMAC MII management command register */
+#define GM_MII_MGMT_CMD_REG_MAC 0x09
+#define GM_MGMT_SCAN_CYC_LBN 1
+#define GM_MGMT_SCAN_CYC_WIDTH 1
+#define GM_MGMT_RD_CYC_LBN 0
+#define GM_MGMT_RD_CYC_WIDTH 1
+
+/* GMAC MII management address register */
+#define GM_MII_MGMT_ADR_REG_MAC 0x0a
+#define GM_MGMT_PHY_ADDR_LBN 8
+#define GM_MGMT_PHY_ADDR_WIDTH 5
+#define GM_MGMT_REG_ADDR_LBN 0
+#define GM_MGMT_REG_ADDR_WIDTH 5
+
+/* GMAC MII management control register */
+#define GM_MII_MGMT_CTL_REG_MAC 0x0b
+#define GM_MGMT_CTL_LBN 0
+#define GM_MGMT_CTL_WIDTH 16
+
+/* GMAC MII management status register */
+#define GM_MII_MGMT_STAT_REG_MAC 0x0c
+#define GM_MGMT_STAT_LBN 0
+#define GM_MGMT_STAT_WIDTH 16
+
+/* GMAC MII management indicators register */
+#define GM_MII_MGMT_IND_REG_MAC 0x0d
+#define GM_MGMT_BUSY_LBN 0
+#define GM_MGMT_BUSY_WIDTH 1
+
+/* GMAC station address register 1 */
+#define GM_ADR1_REG_MAC 0x10
+#define GM_HWADDR_5_LBN 24
+#define GM_HWADDR_5_WIDTH 8
+#define GM_HWADDR_4_LBN 16
+#define GM_HWADDR_4_WIDTH 8
+#define GM_HWADDR_3_LBN 8
+#define GM_HWADDR_3_WIDTH 8
+#define GM_HWADDR_2_LBN 0
+#define GM_HWADDR_2_WIDTH 8
+
+/* GMAC station address register 2 */
+#define GM_ADR2_REG_MAC 0x11
+#define GM_HWADDR_1_LBN 24
+#define GM_HWADDR_1_WIDTH 8
+#define GM_HWADDR_0_LBN 16
+#define GM_HWADDR_0_WIDTH 8
+
+/* GMAC FIFO configuration register 0 */
+#define GMF_CFG0_REG_MAC 0x12
+#define GMF_FTFENREQ_LBN 12
+#define GMF_FTFENREQ_WIDTH 1
+#define GMF_STFENREQ_LBN 11
+#define GMF_STFENREQ_WIDTH 1
+#define GMF_FRFENREQ_LBN 10
+#define GMF_FRFENREQ_WIDTH 1
+#define GMF_SRFENREQ_LBN 9
+#define GMF_SRFENREQ_WIDTH 1
+#define GMF_WTMENREQ_LBN 8
+#define GMF_WTMENREQ_WIDTH 1
+
+/* GMAC FIFO configuration register 1 */
+#define GMF_CFG1_REG_MAC 0x13
+#define GMF_CFGFRTH_LBN 16
+#define GMF_CFGFRTH_WIDTH 5
+#define GMF_CFGXOFFRTX_LBN 0
+#define GMF_CFGXOFFRTX_WIDTH 16
+
+/* GMAC FIFO configuration register 2 */
+#define GMF_CFG2_REG_MAC 0x14
+#define GMF_CFGHWM_LBN 16
+#define GMF_CFGHWM_WIDTH 6
+#define GMF_CFGLWM_LBN 0
+#define GMF_CFGLWM_WIDTH 6
+
+/* GMAC FIFO configuration register 3 */
+#define GMF_CFG3_REG_MAC 0x15
+#define GMF_CFGHWMFT_LBN 16
+#define GMF_CFGHWMFT_WIDTH 6
+#define GMF_CFGFTTH_LBN 0
+#define GMF_CFGFTTH_WIDTH 6
+
+/* GMAC FIFO configuration register 4 */
+#define GMF_CFG4_REG_MAC 0x16
+#define GMF_HSTFLTRFRM_PAUSE_LBN 12
+#define GMF_HSTFLTRFRM_PAUSE_WIDTH 12
+
+/* GMAC FIFO configuration register 5 */
+#define GMF_CFG5_REG_MAC 0x17
+#define GMF_CFGHDPLX_LBN 22
+#define GMF_CFGHDPLX_WIDTH 1
+#define GMF_CFGBYTMODE_LBN 19
+#define GMF_CFGBYTMODE_WIDTH 1
+#define GMF_HSTDRPLT64_LBN 18
+#define GMF_HSTDRPLT64_WIDTH 1
+#define GMF_HSTFLTRFRMDC_PAUSE_LBN 12
+#define GMF_HSTFLTRFRMDC_PAUSE_WIDTH 1
+
+static void
+falcon_gmac_writel ( struct efab_nic *efab, efab_dword_t *value,
+ unsigned int mac_reg )
+{
efab_oword_t temp;
EFAB_POPULATE_OWORD_1 ( temp, FCN_MAC_DATA,
@@ -2584,12 +1905,10 @@ static void falcon_gmac_writel ( struct efab_nic *efab,
falcon_write ( efab, &temp, FALCON_GMAC_REG ( efab, mac_reg ) );
}
-/**
- * Read dword from a Falcon GMAC register
- *
- */
-static void falcon_gmac_readl ( struct efab_nic *efab, efab_dword_t *value,
- unsigned int mac_reg ) {
+static void
+falcon_gmac_readl ( struct efab_nic *efab, efab_dword_t *value,
+ unsigned int mac_reg )
+{
efab_oword_t temp;
falcon_read ( efab, &temp, FALCON_GMAC_REG ( efab, mac_reg ) );
@@ -2597,12 +1916,172 @@ static void falcon_gmac_readl ( struct efab_nic *efab, efab_dword_t *value,
EFAB_OWORD_FIELD ( temp, FCN_MAC_DATA ) );
}
+static void
+mentormac_reset ( struct efab_nic *efab )
+{
+ efab_dword_t reg;
+
+ /* Take into reset */
+ EFAB_POPULATE_DWORD_1 ( reg, GM_SW_RST, 1 );
+ falcon_gmac_writel ( efab, &reg, GM_CFG1_REG_MAC );
+ udelay ( 1000 );
+
+ /* Take out of reset */
+ EFAB_POPULATE_DWORD_1 ( reg, GM_SW_RST, 0 );
+ falcon_gmac_writel ( efab, &reg, GM_CFG1_REG_MAC );
+ udelay ( 1000 );
+
+ /* Configure GMII interface so PHY is accessible. Note that
+ * GMII interface is connected only to port 0, and that on
+ * Falcon this is a no-op.
+ */
+ EFAB_POPULATE_DWORD_1 ( reg, GM_MGMT_CLK_SEL, 0x4 );
+ falcon_gmac_writel ( efab, &reg, GM_MII_MGMT_CFG_REG_MAC );
+ udelay ( 10 );
+}
+
+static void
+mentormac_init ( struct efab_nic *efab )
+{
+ int pause, if_mode, full_duplex, bytemode, half_duplex;
+ efab_dword_t reg;
+
+ /* Configuration register 1 */
+ pause = ( efab->link_options & LPA_PAUSE ) ? 1 : 0;
+ if ( ! ( efab->link_options & LPA_DUPLEX ) ) {
+ /* Half-duplex operation requires TX flow control */
+ pause = 1;
+ }
+ EFAB_POPULATE_DWORD_4 ( reg,
+ GM_TX_EN, 1,
+ GM_TX_FC_EN, pause,
+ GM_RX_EN, 1,
+ GM_RX_FC_EN, 1 );
+ falcon_gmac_writel ( efab, &reg, GM_CFG1_REG_MAC );
+ udelay ( 10 );
+
+ /* Configuration register 2 */
+ if_mode = ( efab->link_options & LPA_1000 ) ? 2 : 1;
+ full_duplex = ( efab->link_options & LPA_DUPLEX ) ? 1 : 0;
+ EFAB_POPULATE_DWORD_4 ( reg,
+ GM_IF_MODE, if_mode,
+ GM_PAD_CRC_EN, 1,
+ GM_FD, full_duplex,
+ GM_PAMBL_LEN, 0x7 /* ? */ );
+ falcon_gmac_writel ( efab, &reg, GM_CFG2_REG_MAC );
+ udelay ( 10 );
+
+ /* Max frame len register */
+ EFAB_POPULATE_DWORD_1 ( reg, GM_MAX_FLEN,
+ EFAB_MAX_FRAME_LEN ( ETH_FRAME_LEN ) );
+ falcon_gmac_writel ( efab, &reg, GM_MAX_FLEN_REG_MAC );
+ udelay ( 10 );
+
+ /* FIFO configuration register 0 */
+ EFAB_POPULATE_DWORD_5 ( reg,
+ GMF_FTFENREQ, 1,
+ GMF_STFENREQ, 1,
+ GMF_FRFENREQ, 1,
+ GMF_SRFENREQ, 1,
+ GMF_WTMENREQ, 1 );
+ falcon_gmac_writel ( efab, &reg, GMF_CFG0_REG_MAC );
+ udelay ( 10 );
+
+ /* FIFO configuration register 1 */
+ EFAB_POPULATE_DWORD_2 ( reg,
+ GMF_CFGFRTH, 0x12,
+ GMF_CFGXOFFRTX, 0xffff );
+ falcon_gmac_writel ( efab, &reg, GMF_CFG1_REG_MAC );
+ udelay ( 10 );
+
+ /* FIFO configuration register 2 */
+ EFAB_POPULATE_DWORD_2 ( reg,
+ GMF_CFGHWM, 0x3f,
+ GMF_CFGLWM, 0xa );
+ falcon_gmac_writel ( efab, &reg, GMF_CFG2_REG_MAC );
+ udelay ( 10 );
+
+ /* FIFO configuration register 3 */
+ EFAB_POPULATE_DWORD_2 ( reg,
+ GMF_CFGHWMFT, 0x1c,
+ GMF_CFGFTTH, 0x08 );
+ falcon_gmac_writel ( efab, &reg, GMF_CFG3_REG_MAC );
+ udelay ( 10 );
+
+ /* FIFO configuration register 4 */
+ EFAB_POPULATE_DWORD_1 ( reg, GMF_HSTFLTRFRM_PAUSE, 1 );
+ falcon_gmac_writel ( efab, &reg, GMF_CFG4_REG_MAC );
+ udelay ( 10 );
+
+ /* FIFO configuration register 5 */
+ bytemode = ( efab->link_options & LPA_1000 ) ? 1 : 0;
+ half_duplex = ( efab->link_options & LPA_DUPLEX ) ? 0 : 1;
+ falcon_gmac_readl ( efab, &reg, GMF_CFG5_REG_MAC );
+ EFAB_SET_DWORD_FIELD ( reg, GMF_CFGBYTMODE, bytemode );
+ EFAB_SET_DWORD_FIELD ( reg, GMF_CFGHDPLX, half_duplex );
+ EFAB_SET_DWORD_FIELD ( reg, GMF_HSTDRPLT64, half_duplex );
+ EFAB_SET_DWORD_FIELD ( reg, GMF_HSTFLTRFRMDC_PAUSE, 0 );
+ falcon_gmac_writel ( efab, &reg, GMF_CFG5_REG_MAC );
+ udelay ( 10 );
+
+ /* MAC address */
+ EFAB_POPULATE_DWORD_4 ( reg,
+ GM_HWADDR_5, efab->mac_addr[5],
+ GM_HWADDR_4, efab->mac_addr[4],
+ GM_HWADDR_3, efab->mac_addr[3],
+ GM_HWADDR_2, efab->mac_addr[2] );
+ falcon_gmac_writel ( efab, &reg, GM_ADR1_REG_MAC );
+ udelay ( 10 );
+ EFAB_POPULATE_DWORD_2 ( reg,
+ GM_HWADDR_1, efab->mac_addr[1],
+ GM_HWADDR_0, efab->mac_addr[0] );
+ falcon_gmac_writel ( efab, &reg, GM_ADR2_REG_MAC );
+ udelay ( 10 );
+}
+
+static int
+falcon_init_gmac ( struct efab_nic *efab )
+{
+ /* Reset the MAC */
+ mentormac_reset ( efab );
+
+ /* Initialise PHY */
+ efab->phy_op->init ( efab );
+
+ /* check the link is up */
+ if ( !efab->link_up )
+ return -EAGAIN;
+
+ /* Initialise MAC */
+ mentormac_init ( efab );
+
+ /* reconfigure the MAC wrapper */
+ falcon_reconfigure_mac_wrapper ( efab );
+
+ return 0;
+}
+
+static struct efab_mac_operations falcon_gmac_operations = {
+ .init = falcon_init_gmac,
+};
+
+
+/*******************************************************************************
+ *
+ *
+ * XMAC handling
+ *
+ *
+ *******************************************************************************/
+
/**
* Write dword to a Falcon XMAC register
*
*/
-static void falcon_xmac_writel ( struct efab_nic *efab,
- efab_dword_t *value, unsigned int mac_reg ) {
+static void
+falcon_xmac_writel ( struct efab_nic *efab, efab_dword_t *value,
+ unsigned int mac_reg )
+{
efab_oword_t temp;
EFAB_POPULATE_OWORD_1 ( temp, FCN_MAC_DATA,
@@ -2615,9 +2094,10 @@ static void falcon_xmac_writel ( struct efab_nic *efab,
* Read dword from a Falcon XMAC register
*
*/
-static void falcon_xmac_readl ( struct efab_nic *efab,
- efab_dword_t *value,
- unsigned int mac_reg ) {
+static void
+falcon_xmac_readl ( struct efab_nic *efab, efab_dword_t *value,
+ unsigned int mac_reg )
+{
efab_oword_t temp;
falcon_read ( efab, &temp,
@@ -2627,109 +2107,159 @@ static void falcon_xmac_readl ( struct efab_nic *efab,
}
/**
- * Initialise GMAC
- *
+ * Configure Falcon XAUI output
*/
-static int falcon_init_gmac ( struct efab_nic *efab ) {
- static struct efab_mentormac_parameters falcon_mentormac_params = {
- .gmf_cfgfrth = 0x12,
- .gmf_cfgftth = 0x08,
- .gmf_cfghwmft = 0x1c,
- .gmf_cfghwm = 0x3f,
- .gmf_cfglwm = 0xa,
- };
+static void
+falcon_setup_xaui ( struct efab_nic *efab )
+{
+ efab_dword_t sdctl, txdrv;
+
+ falcon_xmac_readl ( efab, &sdctl, FCN_XX_SD_CTL_REG_MAC );
+ EFAB_SET_DWORD_FIELD ( sdctl, FCN_XX_HIDRVD, XX_SD_CTL_DRV_DEFAULT );
+ EFAB_SET_DWORD_FIELD ( sdctl, FCN_XX_LODRVD, XX_SD_CTL_DRV_DEFAULT );
+ EFAB_SET_DWORD_FIELD ( sdctl, FCN_XX_HIDRVC, XX_SD_CTL_DRV_DEFAULT );
+ EFAB_SET_DWORD_FIELD ( sdctl, FCN_XX_LODRVC, XX_SD_CTL_DRV_DEFAULT );
+ EFAB_SET_DWORD_FIELD ( sdctl, FCN_XX_HIDRVB, XX_SD_CTL_DRV_DEFAULT );
+ EFAB_SET_DWORD_FIELD ( sdctl, FCN_XX_LODRVB, XX_SD_CTL_DRV_DEFAULT );
+ EFAB_SET_DWORD_FIELD ( sdctl, FCN_XX_HIDRVA, XX_SD_CTL_DRV_DEFAULT );
+ EFAB_SET_DWORD_FIELD ( sdctl, FCN_XX_LODRVA, XX_SD_CTL_DRV_DEFAULT );
+ falcon_xmac_writel ( efab, &sdctl, FCN_XX_SD_CTL_REG_MAC );
+
+ EFAB_POPULATE_DWORD_8 ( txdrv,
+ FCN_XX_DEQD, XX_TXDRV_DEQ_DEFAULT,
+ FCN_XX_DEQC, XX_TXDRV_DEQ_DEFAULT,
+ FCN_XX_DEQB, XX_TXDRV_DEQ_DEFAULT,
+ FCN_XX_DEQA, XX_TXDRV_DEQ_DEFAULT,
+ FCN_XX_DTXD, XX_TXDRV_DTX_DEFAULT,
+ FCN_XX_DTXC, XX_TXDRV_DTX_DEFAULT,
+ FCN_XX_DTXB, XX_TXDRV_DTX_DEFAULT,
+ FCN_XX_DTXA, XX_TXDRV_DTX_DEFAULT);
+ falcon_xmac_writel ( efab, &txdrv, FCN_XX_TXDRV_CTL_REG_MAC);
+}
- /* Initialise PHY */
- alaska_init ( efab );
+static int
+falcon_xgmii_status ( struct efab_nic *efab )
+{
+ efab_dword_t reg;
- /* check the link is up */
- if ( !efab->link_up )
+ if ( efab->pci_revision < FALCON_REV_B0 )
+ return 1;
+ /* The ISR latches, so clear it and re-read */
+ falcon_xmac_readl ( efab, &reg, FCN_XM_MGT_INT_REG_MAC_B0 );
+ falcon_xmac_readl ( efab, &reg, FCN_XM_MGT_INT_REG_MAC_B0 );
+
+ if ( EFAB_DWORD_FIELD ( reg, FCN_XM_LCLFLT ) ||
+ EFAB_DWORD_FIELD ( reg, FCN_XM_RMTFLT ) ) {
+ EFAB_TRACE ( "MGT_INT: "EFAB_DWORD_FMT"\n",
+ EFAB_DWORD_VAL ( reg ) );
return 0;
-
- /* Initialise MAC */
- mentormac_init ( efab, &falcon_mentormac_params );
-
- /* reconfigure the MAC wrapper */
- falcon_reconfigure_mac_wrapper ( efab );
+ }
return 1;
}
-/**
- * Reset GMAC
- *
- */
-static int falcon_reset_gmac ( struct efab_nic *efab ) {
- mentormac_reset ( efab );
- return 1;
+static void
+falcon_mask_status_intr ( struct efab_nic *efab, int enable )
+{
+ efab_dword_t reg;
+
+ if ( efab->pci_revision < FALCON_REV_B0 )
+ return;
+
+ /* Flush the ISR */
+ if ( enable )
+ falcon_xmac_readl ( efab, &reg, FCN_XM_MGT_INT_REG_MAC_B0 );
+
+ EFAB_POPULATE_DWORD_2 ( reg,
+ FCN_XM_MSK_RMTFLT, !enable,
+ FCN_XM_MSK_LCLFLT, !enable);
+ falcon_xmac_readl ( efab, &reg, FCN_XM_MGT_INT_MSK_REG_MAC_B0 );
}
/**
- * Reset XAUI/XGXS block
+ * Reset 10G MAC connected to port
*
*/
-static int falcon_reset_xaui ( struct efab_nic *efab )
+static int
+falcon_reset_xmac ( struct efab_nic *efab )
{
efab_dword_t reg;
int count;
-
- EFAB_POPULATE_DWORD_1 ( reg, FCN_XX_RST_XX_EN, 1 );
- efab->mac_op->mac_writel ( efab, &reg, FCN_XX_PWR_RST_REG_MAC );
+
+ EFAB_POPULATE_DWORD_1 ( reg, FCN_XM_CORE_RST, 1 );
+ falcon_xmac_writel ( efab, &reg, FCN_XM_GLB_CFG_REG_MAC );
for ( count = 0 ; count < 1000 ; count++ ) {
udelay ( 10 );
- efab->mac_op->mac_readl ( efab, &reg,
- FCN_XX_PWR_RST_REG_MAC );
- if ( EFAB_DWORD_FIELD ( reg, FCN_XX_RST_XX_EN ) == 0 )
- return 1;
+ falcon_xmac_readl ( efab, &reg,
+ FCN_XM_GLB_CFG_REG_MAC );
+ if ( EFAB_DWORD_FIELD ( reg, FCN_XM_CORE_RST ) == 0 )
+ return 0;
}
-
- /* an error of some kind */
- return 0;
+ return -ETIMEDOUT;
}
-/**
- * Reset 10G MAC connected to port
- *
- */
-static int falcon_reset_xmac ( struct efab_nic *efab ) {
+
+static int
+falcon_reset_xaui ( struct efab_nic *efab )
+{
efab_dword_t reg;
int count;
- EFAB_POPULATE_DWORD_1 ( reg, FCN_XM_CORE_RST, 1 );
- efab->mac_op->mac_writel ( efab, &reg, FCN_XM_GLB_CFG_REG_MAC );
+ if (!efab->is_asic)
+ return 0;
- for ( count = 0 ; count < 1000 ; count++ ) {
- udelay ( 10 );
- efab->mac_op->mac_readl ( efab, &reg,
- FCN_XM_GLB_CFG_REG_MAC );
- if ( EFAB_DWORD_FIELD ( reg, FCN_XM_CORE_RST ) == 0 )
- return 1;
+ EFAB_POPULATE_DWORD_1 ( reg, FCN_XX_RST_XX_EN, 1 );
+ falcon_xmac_writel ( efab, &reg, FCN_XX_PWR_RST_REG_MAC );
+
+ /* Give some time for the link to establish */
+ for (count = 0; count < 1000; count++) { /* wait upto 10ms */
+ falcon_xmac_readl ( efab, &reg, FCN_XX_PWR_RST_REG_MAC );
+ if ( EFAB_DWORD_FIELD ( reg, FCN_XX_RST_XX_EN ) == 0 ) {
+ falcon_setup_xaui ( efab );
+ return 0;
+ }
+ udelay(10);
}
- return 0;
+ EFAB_ERR ( "timed out waiting for XAUI/XGXS reset\n" );
+ return -ETIMEDOUT;
}
-/**
- * Get status of 10G link
- *
- */
-static int falcon_xaui_link_ok ( struct efab_nic *efab ) {
+static int
+falcon_xaui_link_ok ( struct efab_nic *efab )
+{
efab_dword_t reg;
- int align_done;
- int sync_status;
- int link_ok = 0;
+ int align_done, lane_status, sync;
+ int has_phyxs;
+ int link_ok = 1;
+
+ /* Read Falcon XAUI side */
+ if ( efab->is_asic ) {
+ /* Read link status */
+ falcon_xmac_readl ( efab, &reg, FCN_XX_CORE_STAT_REG_MAC );
+ align_done = EFAB_DWORD_FIELD ( reg, FCN_XX_ALIGN_DONE );
- /* Read link status */
- efab->mac_op->mac_readl ( efab, &reg, FCN_XX_CORE_STAT_REG_MAC );
- align_done = EFAB_DWORD_FIELD ( reg, FCN_XX_ALIGN_DONE );
- sync_status = EFAB_DWORD_FIELD ( reg, FCN_XX_SYNC_STAT );
- if ( align_done && ( sync_status == FCN_XX_SYNC_STAT_DECODE_SYNCED ) ) {
- link_ok = 1;
+ sync = EFAB_DWORD_FIELD ( reg, FCN_XX_SYNC_STAT );
+ sync = ( sync == FCN_XX_SYNC_STAT_DECODE_SYNCED );
+
+ link_ok = align_done && sync;
}
/* Clear link status ready for next read */
EFAB_SET_DWORD_FIELD ( reg, FCN_XX_COMMA_DET, FCN_XX_COMMA_DET_RESET );
- efab->mac_op->mac_writel ( efab, &reg, FCN_XX_CORE_STAT_REG_MAC );
+ EFAB_SET_DWORD_FIELD ( reg, FCN_XX_CHARERR, FCN_XX_CHARERR_RESET);
+ EFAB_SET_DWORD_FIELD ( reg, FCN_XX_DISPERR, FCN_XX_DISPERR_RESET);
+ falcon_xmac_writel ( efab, &reg, FCN_XX_CORE_STAT_REG_MAC );
+
+ has_phyxs = ( efab->phy_op->mmds & ( 1 << MDIO_MMD_PHYXS ) );
+ if ( link_ok && has_phyxs ) {
+ lane_status = falcon_mdio_read ( efab, MDIO_MMD_PHYXS,
+ MDIO_PHYXS_LANE_STATE );
+ link_ok = ( lane_status & ( 1 << MDIO_PHYXS_LANE_ALIGNED_LBN ) );
+
+ if (!link_ok )
+ EFAB_LOG ( "XGXS lane status: %x\n", lane_status );
+ }
return link_ok;
}
@@ -2738,28 +2268,18 @@ static int falcon_xaui_link_ok ( struct efab_nic *efab ) {
* Initialise XMAC
*
*/
-static int falcon_init_xmac ( struct efab_nic *efab ) {
+static void
+falcon_reconfigure_xmac ( struct efab_nic *efab )
+{
efab_dword_t reg;
- int count;
+ int max_frame_len;
- if ( !falcon_reset_xmac ( efab ) ) {
- EFAB_ERR ( "failed resetting XMAC\n" );
- return 0;
- }
- if ( !falcon_reset_xaui ( efab ) ) {
- EFAB_ERR ( "failed resetting XAUI\n");
- return 0;
- }
-
- /* CX4 is always 10000FD only */
- efab->link_options = LPA_10000FULL;
-
- /* Configure MAC */
+ /* Configure MAC - cut-thru mode is hard wired on */
EFAB_POPULATE_DWORD_3 ( reg,
FCN_XM_RX_JUMBO_MODE, 1,
FCN_XM_TX_STAT_EN, 1,
FCN_XM_RX_STAT_EN, 1);
- efab->mac_op->mac_writel ( efab, &reg, FCN_XM_GLB_CFG_REG_MAC );
+ falcon_xmac_writel ( efab, &reg, FCN_XM_GLB_CFG_REG_MAC );
/* Configure TX */
EFAB_POPULATE_DWORD_6 ( reg,
@@ -2769,23 +2289,31 @@ static int falcon_init_xmac ( struct efab_nic *efab ) {
FCN_XM_TXCRC, 1,
FCN_XM_FCNTL, 1,
FCN_XM_IPG, 0x3 );
- efab->mac_op->mac_writel ( efab, &reg, FCN_XM_TX_CFG_REG_MAC );
+ falcon_xmac_writel ( efab, &reg, FCN_XM_TX_CFG_REG_MAC );
/* Configure RX */
- EFAB_POPULATE_DWORD_3 ( reg,
+ EFAB_POPULATE_DWORD_4 ( reg,
FCN_XM_RXEN, 1,
- FCN_XM_AUTO_DEPAD, 1,
+ FCN_XM_AUTO_DEPAD, 0,
+ FCN_XM_ACPT_ALL_MCAST, 1,
FCN_XM_PASS_CRC_ERR, 1 );
- efab->mac_op->mac_writel ( efab, &reg, FCN_XM_RX_CFG_REG_MAC );
+ falcon_xmac_writel ( efab, &reg, FCN_XM_RX_CFG_REG_MAC );
/* Set frame length */
+ max_frame_len = EFAB_MAX_FRAME_LEN ( ETH_FRAME_LEN );
EFAB_POPULATE_DWORD_1 ( reg,
- FCN_XM_MAX_RX_FRM_SIZE, ETH_FRAME_LEN );
- efab->mac_op->mac_writel ( efab, &reg, FCN_XM_RX_PARAM_REG_MAC );
+ FCN_XM_MAX_RX_FRM_SIZE, max_frame_len );
+ falcon_xmac_writel ( efab, &reg, FCN_XM_RX_PARAM_REG_MAC );
EFAB_POPULATE_DWORD_2 ( reg,
- FCN_XM_MAX_TX_FRM_SIZE, ETH_FRAME_LEN,
+ FCN_XM_MAX_TX_FRM_SIZE, max_frame_len,
FCN_XM_TX_JUMBO_MODE, 1 );
- efab->mac_op->mac_writel ( efab, &reg, FCN_XM_TX_PARAM_REG_MAC );
+ falcon_xmac_writel ( efab, &reg, FCN_XM_TX_PARAM_REG_MAC );
+
+ /* Enable flow control receipt */
+ EFAB_POPULATE_DWORD_2 ( reg,
+ FCN_XM_PAUSE_TIME, 0xfffe,
+ FCN_XM_DIS_FCNTL, 0 );
+ falcon_xmac_writel ( efab, &reg, FCN_XM_FC_REG_MAC );
/* Set MAC address */
EFAB_POPULATE_DWORD_4 ( reg,
@@ -2793,639 +2321,1921 @@ static int falcon_init_xmac ( struct efab_nic *efab ) {
FCN_XM_ADR_1, efab->mac_addr[1],
FCN_XM_ADR_2, efab->mac_addr[2],
FCN_XM_ADR_3, efab->mac_addr[3] );
- efab->mac_op->mac_writel ( efab, &reg, FCN_XM_ADR_LO_REG_MAC );
+ falcon_xmac_writel ( efab, &reg, FCN_XM_ADR_LO_REG_MAC );
EFAB_POPULATE_DWORD_2 ( reg,
FCN_XM_ADR_4, efab->mac_addr[4],
FCN_XM_ADR_5, efab->mac_addr[5] );
- efab->mac_op->mac_writel ( efab, &reg, FCN_XM_ADR_HI_REG_MAC );
+ falcon_xmac_writel ( efab, &reg, FCN_XM_ADR_HI_REG_MAC );
+}
- /* Reconfigure MAC wrapper */
- falcon_reconfigure_mac_wrapper ( efab );
+static int
+falcon_init_xmac ( struct efab_nic *efab )
+{
+ int count, rc;
+
+ /* Mask the PHY management interrupt */
+ falcon_mask_status_intr ( efab, 0 );
+ /* Initialise the PHY to instantiate the clock. */
+ rc = efab->phy_op->init ( efab );
+ if ( rc ) {
+ EFAB_ERR ( "unable to initialise PHY\n" );
+ goto fail1;
+ }
+
+ falcon_reset_xaui ( efab );
+
+ /* Give the PHY and MAC time to faff */
+ mdelay ( 100 );
+
+ /* Reset and reconfigure the XMAC */
+ rc = falcon_reset_xmac ( efab );
+ if ( rc )
+ goto fail2;
+ falcon_reconfigure_xmac ( efab );
+ falcon_reconfigure_mac_wrapper ( efab );
/**
- * Try resetting XAUI on its own waiting for the link
- * to come up
+ * Now wait for the link to come up. This may take a while
+ * for some slower PHY's.
*/
- for(count=0; count<5; count++) {
- /* Check link status */
- efab->link_up = falcon_xaui_link_ok ( efab );
- if ( efab->link_up ) {
- /**
- * Print out a speed message since we don't have a PHY
- */
- EFAB_LOG ( "%dMbps %s-duplex\n",
- ( efab->link_options & LPA_10000 ? 1000 :
- ( efab->link_options & LPA_1000 ? 1000 :
- ( efab->link_options & LPA_100 ? 100 : 10 ) ) ),
- ( efab->link_options & LPA_DUPLEX ? "full" : "half" ) );
- break;
+ for (count=0; count<50; count++) {
+ int link_ok = 1;
+
+ /* Wait a while for the link to come up. */
+ mdelay ( 100 );
+ if ((count % 5) == 0)
+ putchar ( '.' );
+
+ /* Does the PHY think the wire-side link is up? */
+ link_ok = mdio_clause45_links_ok ( efab );
+ /* Ensure the XAUI link to the PHY is good */
+ if ( link_ok ) {
+ link_ok = falcon_xaui_link_ok ( efab );
+ if ( !link_ok )
+ falcon_reset_xaui ( efab );
}
- if ( !falcon_reset_xaui ( efab ) ) {
- EFAB_ERR ( "failed resetting xaui\n" );
+ /* Check fault indication */
+ if ( link_ok )
+ link_ok = falcon_xgmii_status ( efab );
+
+ efab->link_up = link_ok;
+ if ( link_ok ) {
+ /* unmask the status interrupt */
+ falcon_mask_status_intr ( efab, 1 );
return 0;
}
- udelay(100);
}
- return 1;
+ /* Link failed to come up, but initialisation was fine. */
+ rc = -ETIMEDOUT;
+
+fail2:
+fail1:
+ return rc;
+}
+
+static struct efab_mac_operations falcon_xmac_operations = {
+ .init = falcon_init_xmac,
+};
+
+/*******************************************************************************
+ *
+ *
+ * Null PHY handling
+ *
+ *
+ *******************************************************************************/
+
+static int
+falcon_xaui_phy_init ( struct efab_nic *efab )
+{
+ /* CX4 is always 10000FD only */
+ efab->link_options = LPA_10000FULL;
+
+ /* There is no PHY! */
+ return 0;
}
+static struct efab_phy_operations falcon_xaui_phy_ops = {
+ .init = falcon_xaui_phy_init,
+ .mmds = 0,
+};
+
+
+/*******************************************************************************
+ *
+ *
+ * Alaska PHY
+ *
+ *
+ *******************************************************************************/
+
/**
- * Wait for GMII access to complete
+ * Initialise Alaska PHY
*
*/
-static int falcon_gmii_wait ( struct efab_nic *efab ) {
- efab_oword_t md_stat;
+static int
+alaska_init ( struct efab_nic *efab )
+{
+ unsigned int advertised, lpa;
+
+ /* Read link up status */
+ efab->link_up = gmii_link_ok ( efab );
+
+ if ( ! efab->link_up )
+ return -EIO;
+
+ /* Determine link options from PHY. */
+ advertised = gmii_autoneg_advertised ( efab );
+ lpa = gmii_autoneg_lpa ( efab );
+ efab->link_options = gmii_nway_result ( advertised & lpa );
+
+ return 0;
+}
+
+static struct efab_phy_operations falcon_alaska_phy_ops = {
+ .init = alaska_init,
+};
+
+/*******************************************************************************
+ *
+ *
+ * xfp
+ *
+ *
+ *******************************************************************************/
+
+#define XFP_REQUIRED_DEVS ( MDIO_MMDREG_DEVS0_PCS | \
+ MDIO_MMDREG_DEVS0_PMAPMD | \
+ MDIO_MMDREG_DEVS0_PHYXS )
+
+static int
+falcon_xfp_phy_init ( struct efab_nic *efab )
+{
+ int rc;
+
+ /* Optical link is always 10000FD only */
+ efab->link_options = LPA_10000FULL;
+
+ /* Reset the PHY */
+ rc = mdio_clause45_reset_mmd ( efab, MDIO_MMD_PHYXS );
+ if ( rc )
+ return rc;
+
+ return 0;
+}
+
+static struct efab_phy_operations falcon_xfp_phy_ops = {
+ .init = falcon_xfp_phy_init,
+ .mmds = XFP_REQUIRED_DEVS,
+};
+
+/*******************************************************************************
+ *
+ *
+ * txc43128
+ *
+ *
+ *******************************************************************************/
+
+/* Command register */
+#define TXC_GLRGS_GLCMD (0xc004)
+#define TXC_GLCMD_LMTSWRST_LBN (14)
+
+/* Amplitude on lanes 0+1, 2+3 */
+#define TXC_ALRGS_ATXAMP0 (0xc041)
+#define TXC_ALRGS_ATXAMP1 (0xc042)
+/* Bit position of value for lane 0+2, 1+3 */
+#define TXC_ATXAMP_LANE02_LBN (3)
+#define TXC_ATXAMP_LANE13_LBN (11)
+
+#define TXC_ATXAMP_1280_mV (0)
+#define TXC_ATXAMP_1200_mV (8)
+#define TXC_ATXAMP_1120_mV (12)
+#define TXC_ATXAMP_1060_mV (14)
+#define TXC_ATXAMP_0820_mV (25)
+#define TXC_ATXAMP_0720_mV (26)
+#define TXC_ATXAMP_0580_mV (27)
+#define TXC_ATXAMP_0440_mV (28)
+
+#define TXC_ATXAMP_0820_BOTH ( (TXC_ATXAMP_0820_mV << TXC_ATXAMP_LANE02_LBN) | \
+ (TXC_ATXAMP_0820_mV << TXC_ATXAMP_LANE13_LBN) )
+
+#define TXC_ATXAMP_DEFAULT (0x6060) /* From databook */
+
+/* Preemphasis on lanes 0+1, 2+3 */
+#define TXC_ALRGS_ATXPRE0 (0xc043)
+#define TXC_ALRGS_ATXPRE1 (0xc044)
+
+#define TXC_ATXPRE_NONE (0)
+#define TXC_ATXPRE_DEFAULT (0x1010) /* From databook */
+
+#define TXC_REQUIRED_DEVS ( MDIO_MMDREG_DEVS0_PCS | \
+ MDIO_MMDREG_DEVS0_PMAPMD | \
+ MDIO_MMDREG_DEVS0_PHYXS )
+
+static int
+falcon_txc_logic_reset ( struct efab_nic *efab )
+{
+ int val;
+ int tries = 50;
+
+ val = falcon_mdio_read ( efab, MDIO_MMD_PCS, TXC_GLRGS_GLCMD );
+ val |= (1 << TXC_GLCMD_LMTSWRST_LBN);
+ falcon_mdio_write ( efab, MDIO_MMD_PCS, TXC_GLRGS_GLCMD, val );
+
+ while ( tries--) {
+ val = falcon_mdio_read ( efab, MDIO_MMD_PCS, TXC_GLRGS_GLCMD );
+ if ( ~val & ( 1 << TXC_GLCMD_LMTSWRST_LBN ) )
+ return 0;
+ udelay(1);
+ }
+
+ EFAB_ERR ( "logic reset failed\n" );
+
+ return -ETIMEDOUT;
+}
+
+static int
+falcon_txc_phy_init ( struct efab_nic *efab )
+{
+ int rc;
+
+ /* CX4 is always 10000FD only */
+ efab->link_options = LPA_10000FULL;
+
+ /* reset the phy */
+ rc = mdio_clause45_reset_mmd ( efab, MDIO_MMD_PMAPMD );
+ if ( rc )
+ goto fail1;
+
+ rc = mdio_clause45_check_mmds ( efab );
+ if ( rc )
+ goto fail2;
+
+ /* Turn amplitude down and preemphasis off on the host side
+ * (PHY<->MAC) as this is believed less likely to upset falcon
+ * and no adverse effects have been noted. It probably also
+ * saves a picowatt or two */
+
+ /* Turn off preemphasis */
+ falcon_mdio_write ( efab, MDIO_MMD_PHYXS, TXC_ALRGS_ATXPRE0,
+ TXC_ATXPRE_NONE );
+ falcon_mdio_write ( efab, MDIO_MMD_PHYXS, TXC_ALRGS_ATXPRE1,
+ TXC_ATXPRE_NONE );
+
+ /* Turn down the amplitude */
+ falcon_mdio_write ( efab, MDIO_MMD_PHYXS, TXC_ALRGS_ATXAMP0,
+ TXC_ATXAMP_0820_BOTH );
+ falcon_mdio_write ( efab, MDIO_MMD_PHYXS, TXC_ALRGS_ATXAMP1,
+ TXC_ATXAMP_0820_BOTH );
+
+ /* Set the line side amplitude and preemphasis to the databook
+ * defaults as an erratum causes them to be 0 on at least some
+ * PHY rev.s */
+ falcon_mdio_write ( efab, MDIO_MMD_PMAPMD, TXC_ALRGS_ATXPRE0,
+ TXC_ATXPRE_DEFAULT );
+ falcon_mdio_write ( efab, MDIO_MMD_PMAPMD, TXC_ALRGS_ATXPRE1,
+ TXC_ATXPRE_DEFAULT );
+ falcon_mdio_write ( efab, MDIO_MMD_PMAPMD, TXC_ALRGS_ATXAMP0,
+ TXC_ATXAMP_DEFAULT );
+ falcon_mdio_write ( efab, MDIO_MMD_PMAPMD, TXC_ALRGS_ATXAMP1,
+ TXC_ATXAMP_DEFAULT );
+
+ rc = falcon_txc_logic_reset ( efab );
+ if ( rc )
+ goto fail3;
+
+ return 0;
+
+fail3:
+fail2:
+fail1:
+ return rc;
+}
+
+static struct efab_phy_operations falcon_txc_phy_ops = {
+ .init = falcon_txc_phy_init,
+ .mmds = TXC_REQUIRED_DEVS,
+};
+
+/*******************************************************************************
+ *
+ *
+ * tenxpress
+ *
+ *
+ *******************************************************************************/
+
+
+#define TENXPRESS_REQUIRED_DEVS ( MDIO_MMDREG_DEVS0_PMAPMD | \
+ MDIO_MMDREG_DEVS0_PCS | \
+ MDIO_MMDREG_DEVS0_PHYXS )
+
+#define PCS_TEST_SELECT_REG 0xd807 /* PRM 10.5.8 */
+#define CLK312_EN_LBN 3
+#define CLK312_EN_WIDTH 1
+
+#define PCS_CLOCK_CTRL_REG 0xd801
+#define PLL312_RST_N_LBN 2
+
+/* Special Software reset register */
+#define PMA_PMD_EXT_CTRL_REG 49152
+#define PMA_PMD_EXT_SSR_LBN 15
+
+/* Boot status register */
+#define PCS_BOOT_STATUS_REG 0xd000
+#define PCS_BOOT_FATAL_ERR_LBN 0
+#define PCS_BOOT_PROGRESS_LBN 1
+#define PCS_BOOT_PROGRESS_WIDTH 2
+#define PCS_BOOT_COMPLETE_LBN 3
+
+#define PCS_SOFT_RST2_REG 0xd806
+#define SERDES_RST_N_LBN 13
+#define XGXS_RST_N_LBN 12
+
+static int
+falcon_tenxpress_check_c11 ( struct efab_nic *efab )
+{
int count;
+ uint32_t boot_stat;
- for ( count = 0 ; count < 1000 ; count++ ) {
- udelay ( 10 );
- falcon_read ( efab, &md_stat, FCN_MD_STAT_REG_KER );
- if ( EFAB_OWORD_FIELD ( md_stat, FCN_MD_BSY ) == 0 )
- return 1;
+ /* Check that the C11 CPU has booted */
+ for (count=0; count<10; count++) {
+ boot_stat = falcon_mdio_read ( efab, MDIO_MMD_PCS,
+ PCS_BOOT_STATUS_REG );
+ if ( boot_stat & ( 1 << PCS_BOOT_COMPLETE_LBN ) )
+ return 0;
+
+ udelay(10);
}
- EFAB_ERR ( "Timed out waiting for GMII\n" );
+
+ EFAB_ERR ( "C11 failed to boot\n" );
+ return -ETIMEDOUT;
+}
+
+static int
+falcon_tenxpress_phy_init ( struct efab_nic *efab )
+{
+ int rc, reg;
+
+ /* 10XPRESS is always 10000FD (at the moment) */
+ efab->link_options = LPA_10000FULL;
+
+ /* Wait for the blocks to come out of reset */
+ rc = mdio_clause45_wait_reset_mmds ( efab );
+ if ( rc )
+ goto fail1;
+
+ rc = mdio_clause45_check_mmds ( efab );
+ if ( rc )
+ goto fail2;
+
+ /* Turn on the clock */
+ reg = (1 << CLK312_EN_LBN);
+ falcon_mdio_write ( efab, MDIO_MMD_PCS, PCS_TEST_SELECT_REG, reg);
+
+ /* Wait 200ms for the PHY to boot */
+ mdelay(200);
+
+ rc = falcon_tenxpress_check_c11 ( efab );
+ if ( rc )
+ goto fail3;
+
return 0;
+
+fail3:
+fail2:
+fail1:
+ return rc;
}
+static struct efab_phy_operations falcon_tenxpress_phy_ops = {
+ .init = falcon_tenxpress_phy_init,
+ .mmds = TENXPRESS_REQUIRED_DEVS,
+};
-static struct efab_mac_operations falcon_xmac_operations = {
- .mac_readl = falcon_xmac_readl,
- .mac_writel = falcon_xmac_writel,
- .init = falcon_init_xmac,
- .reset = falcon_reset_xmac,
+/*******************************************************************************
+ *
+ *
+ * PM8358
+ *
+ *
+ *******************************************************************************/
+
+/* The PM8358 just presents a DTE XS */
+#define PM8358_REQUIRED_DEVS (MDIO_MMDREG_DEVS0_DTEXS)
+
+/* PHY-specific definitions */
+/* Master ID and Global Performance Monitor Update */
+#define PMC_MASTER_REG (0xd000)
+/* Analog Tx Rx settings under software control */
+#define PMC_MASTER_ANLG_CTRL (1<< 11)
+
+/* Master Configuration register 2 */
+#define PMC_MCONF2_REG (0xd002)
+/* Drive Tx off centre of data eye (1) vs. clock edge (0) */
+#define PMC_MCONF2_TEDGE (1 << 2)
+/* Drive Rx off centre of data eye (1) vs. clock edge (0) */
+#define PMC_MCONF2_REDGE (1 << 3)
+
+/* Analog Rx settings */
+#define PMC_ANALOG_RX_CFG0 (0xd025)
+#define PMC_ANALOG_RX_CFG1 (0xd02d)
+#define PMC_ANALOG_RX_CFG2 (0xd035)
+#define PMC_ANALOG_RX_CFG3 (0xd03d)
+
+
+#define PMC_ANALOG_RX_TERM (1 << 15) /* Bit 15 of RX CFG: 0 for 100 ohms float,
+ 1 for 50 to 1.2V */
+#define PMC_ANALOG_RX_EQ_MASK (3 << 8)
+#define PMC_ANALOG_RX_EQ_NONE (0 << 8)
+#define PMC_ANALOG_RX_EQ_HALF (1 << 8)
+#define PMC_ANALOG_RX_EQ_FULL (2 << 8)
+#define PMC_ANALOG_RX_EQ_RSVD (3 << 8)
+
+static int
+falcon_pm8358_phy_init ( struct efab_nic *efab )
+{
+ int rc, reg, i;
+
+ /* This is a XAUI retimer part */
+ efab->link_options = LPA_10000FULL;
+
+ rc = mdio_clause45_reset_mmd ( efab, MDIO_MMDREG_DEVS0_DTEXS );
+ if ( rc )
+ return rc;
+
+ /* Enable software control of analogue settings */
+ reg = falcon_mdio_read ( efab, MDIO_MMD_DTEXS, PMC_MASTER_REG );
+ reg |= PMC_MASTER_ANLG_CTRL;
+ falcon_mdio_write ( efab, MDIO_MMD_DTEXS, PMC_MASTER_REG, reg );
+
+ /* Turn rx eq on for all channels */
+ for (i=0; i< 3; i++) {
+ /* The analog CFG registers are evenly spaced 8 apart */
+ uint16_t addr = PMC_ANALOG_RX_CFG0 + 8*i;
+ reg = falcon_mdio_read ( efab, MDIO_MMD_DTEXS, addr );
+ reg = ( reg & ~PMC_ANALOG_RX_EQ_MASK ) | PMC_ANALOG_RX_EQ_FULL;
+ falcon_mdio_write ( efab, MDIO_MMD_DTEXS, addr, reg );
+ }
+
+ /* Set TEDGE, clear REDGE */
+ reg = falcon_mdio_read ( efab, MDIO_MMD_DTEXS, PMC_MCONF2_REG );
+ reg = ( reg & ~PMC_MCONF2_REDGE) | PMC_MCONF2_TEDGE;
+ falcon_mdio_write ( efab, MDIO_MMD_DTEXS, PMC_MCONF2_REG, reg );
+
+ return 0;
+}
+
+static struct efab_phy_operations falcon_pm8358_phy_ops = {
+ .init = falcon_pm8358_phy_init,
+ .mmds = PM8358_REQUIRED_DEVS,
};
-static struct efab_mac_operations falcon_gmac_operations = {
- .mac_readl = falcon_gmac_readl,
- .mac_writel = falcon_gmac_writel,
- .init = falcon_init_gmac,
- .reset = falcon_reset_gmac,
+/*******************************************************************************
+ *
+ *
+ * SFE4001 support
+ *
+ *
+ *******************************************************************************/
+
+#define MAX_TEMP_THRESH 90
+
+/* I2C Expander */
+#define PCA9539 0x74
+
+#define P0_IN 0x00
+#define P0_OUT 0x02
+#define P0_CONFIG 0x06
+
+#define P0_EN_1V0X_LBN 0
+#define P0_EN_1V0X_WIDTH 1
+#define P0_EN_1V2_LBN 1
+#define P0_EN_1V2_WIDTH 1
+#define P0_EN_2V5_LBN 2
+#define P0_EN_2V5_WIDTH 1
+#define P0_EN_3V3X_LBN 3
+#define P0_EN_3V3X_WIDTH 1
+#define P0_EN_5V_LBN 4
+#define P0_EN_5V_WIDTH 1
+#define P0_X_TRST_LBN 6
+#define P0_X_TRST_WIDTH 1
+
+#define P1_IN 0x01
+#define P1_CONFIG 0x07
+
+#define P1_AFE_PWD_LBN 0
+#define P1_AFE_PWD_WIDTH 1
+#define P1_DSP_PWD25_LBN 1
+#define P1_DSP_PWD25_WIDTH 1
+#define P1_SPARE_LBN 4
+#define P1_SPARE_WIDTH 4
+
+/* Temperature Sensor */
+#define MAX6647 0x4e
+
+#define RSL 0x02
+#define RLHN 0x05
+#define WLHO 0x0b
+
+static struct i2c_device i2c_pca9539 = {
+ .dev_addr = PCA9539,
+ .dev_addr_len = 1,
+ .word_addr_len = 1,
};
-/**
- * Initialise NIC
+static struct i2c_device i2c_max6647 = {
+ .dev_addr = MAX6647,
+ .dev_addr_len = 1,
+ .word_addr_len = 1,
+};
+
+static int
+sfe4001_init ( struct efab_nic *efab )
+{
+ struct i2c_interface *i2c = &efab->i2c_bb.i2c;
+ efab_dword_t reg;
+ uint8_t in, cfg, out;
+ int count, rc;
+
+ EFAB_LOG ( "Initialise SFE4001 board\n" );
+
+ /* Ensure XGXS and XAUI SerDes are held in reset */
+ EFAB_POPULATE_DWORD_7 ( reg,
+ FCN_XX_PWRDNA_EN, 1,
+ FCN_XX_PWRDNB_EN, 1,
+ FCN_XX_RSTPLLAB_EN, 1,
+ FCN_XX_RESETA_EN, 1,
+ FCN_XX_RESETB_EN, 1,
+ FCN_XX_RSTXGXSRX_EN, 1,
+ FCN_XX_RSTXGXSTX_EN, 1 );
+ falcon_xmac_writel ( efab, &reg, FCN_XX_PWR_RST_REG_MAC);
+ udelay(10);
+
+ /* Set DSP over-temperature alert threshold */
+ cfg = MAX_TEMP_THRESH;
+ rc = i2c->write ( i2c, &i2c_max6647, WLHO, &cfg, EFAB_BYTE );
+ if ( rc )
+ goto fail1;
+
+ /* Read it back and verify */
+ rc = i2c->read ( i2c, &i2c_max6647, RLHN, &in, EFAB_BYTE );
+ if ( rc )
+ goto fail2;
+
+ if ( in != MAX_TEMP_THRESH ) {
+ EFAB_ERR ( "Unable to verify MAX6647 limit (requested=%d "
+ "confirmed=%d)\n", cfg, in );
+ rc = -EIO;
+ goto fail3;
+ }
+
+ /* Clear any previous over-temperature alert */
+ rc = i2c->read ( i2c, &i2c_max6647, RSL, &in, EFAB_BYTE );
+ if ( rc )
+ goto fail4;
+
+ /* Enable port 0 and 1 outputs on IO expander */
+ cfg = 0x00;
+ rc = i2c->write ( i2c, &i2c_pca9539, P0_CONFIG, &cfg, EFAB_BYTE );
+ if ( rc )
+ goto fail5;
+ cfg = 0xff & ~(1 << P1_SPARE_LBN);
+ rc = i2c->write ( i2c, &i2c_pca9539, P1_CONFIG, &cfg, EFAB_BYTE );
+ if ( rc )
+ goto fail6;
+
+ /* Turn all power off then wait 1 sec. This ensures PHY is reset */
+ out = 0xff & ~((0 << P0_EN_1V2_LBN) | (0 << P0_EN_2V5_LBN) |
+ (0 << P0_EN_3V3X_LBN) | (0 << P0_EN_5V_LBN) |
+ (0 << P0_EN_1V0X_LBN));
+
+ rc = i2c->write ( i2c, &i2c_pca9539, P0_OUT, &out, EFAB_BYTE );
+ if ( rc )
+ goto fail7;
+
+ mdelay(1000);
+
+ for (count=0; count<20; count++) {
+ /* Turn on 1.2V, 2.5V, 3.3V and 5V power rails */
+ out = 0xff & ~( (1 << P0_EN_1V2_LBN) | (1 << P0_EN_2V5_LBN) |
+ (1 << P0_EN_3V3X_LBN) | (1 << P0_EN_5V_LBN) |
+ (1 << P0_X_TRST_LBN) );
+
+ rc = i2c->write ( i2c, &i2c_pca9539, P0_OUT, &out, EFAB_BYTE );
+ if ( rc )
+ goto fail8;
+
+ mdelay ( 10 );
+
+ /* Turn on the 1V power rail */
+ out &= ~( 1 << P0_EN_1V0X_LBN );
+ rc = i2c->write ( i2c, &i2c_pca9539, P0_OUT, &out, EFAB_BYTE );
+ if ( rc )
+ goto fail9;
+
+ EFAB_LOG ( "Waiting for power...(attempt %d)\n", count);
+ mdelay ( 1000 );
+
+ /* Check DSP is powered */
+ rc = i2c->read ( i2c, &i2c_pca9539, P1_IN, &in, EFAB_BYTE );
+ if ( rc )
+ goto fail10;
+
+ if ( in & ( 1 << P1_AFE_PWD_LBN ) )
+ return 0;
+ }
+
+ rc = -ETIMEDOUT;
+
+fail10:
+fail9:
+fail8:
+fail7:
+ /* Turn off power rails */
+ out = 0xff;
+ (void) i2c->write ( i2c, &i2c_pca9539, P0_OUT, &out, EFAB_BYTE );
+ /* Disable port 1 outputs on IO expander */
+ out = 0xff;
+ (void) i2c->write ( i2c, &i2c_pca9539, P1_CONFIG, &out, EFAB_BYTE );
+fail6:
+ /* Disable port 0 outputs */
+ out = 0xff;
+ (void) i2c->write ( i2c, &i2c_pca9539, P1_CONFIG, &out, EFAB_BYTE );
+fail5:
+fail4:
+fail3:
+fail2:
+fail1:
+ EFAB_ERR ( "Failed initialising SFE4001 board\n" );
+ return rc;
+}
+
+static void
+sfe4001_fini ( struct efab_nic *efab )
+{
+ struct i2c_interface *i2c = &efab->i2c_bb.i2c;
+ uint8_t in, cfg, out;
+
+ EFAB_ERR ( "Turning off SFE4001\n" );
+
+ /* Turn off all power rails */
+ out = 0xff;
+ (void) i2c->write ( i2c, &i2c_pca9539, P0_OUT, &out, EFAB_BYTE );
+
+ /* Disable port 1 outputs on IO expander */
+ cfg = 0xff;
+ (void) i2c->write ( i2c, &i2c_pca9539, P1_CONFIG, &cfg, EFAB_BYTE );
+
+ /* Disable port 0 outputs on IO expander */
+ cfg = 0xff;
+ (void) i2c->write ( i2c, &i2c_pca9539, P0_CONFIG, &cfg, EFAB_BYTE );
+
+ /* Clear any over-temperature alert */
+ (void) i2c->read ( i2c, &i2c_max6647, RSL, &in, EFAB_BYTE );
+}
+
+struct efab_board_operations sfe4001_ops = {
+ .init = sfe4001_init,
+ .fini = sfe4001_fini,
+};
+
+static int sfe4002_init ( struct efab_nic *efab __attribute__((unused)) )
+{
+ return 0;
+}
+static void sfe4002_fini ( struct efab_nic *efab __attribute__((unused)) )
+{
+}
+
+struct efab_board_operations sfe4002_ops = {
+ .init = sfe4002_init,
+ .fini = sfe4002_fini,
+};
+
+static int sfe4003_init ( struct efab_nic *efab __attribute__((unused)) )
+{
+ return 0;
+}
+static void sfe4003_fini ( struct efab_nic *efab __attribute__((unused)) )
+{
+}
+
+struct efab_board_operations sfe4003_ops = {
+ .init = sfe4003_init,
+ .fini = sfe4003_fini,
+};
+
+/*******************************************************************************
*
- */
-static int falcon_init_nic ( struct efab_nic *efab ) {
- efab_oword_t reg;
- efab_dword_t timer_cmd;
- int version, minor;
+ *
+ * Hardware initialisation
+ *
+ *
+ *******************************************************************************/
- /* use card in internal SRAM mode */
- falcon_read ( efab, &reg, FCN_NIC_STAT_REG );
- EFAB_SET_OWORD_FIELD ( reg, ONCHIP_SRAM, 1 );
- falcon_write ( efab, &reg, FCN_NIC_STAT_REG );
- wmb();
+static void
+falcon_free_special_buffer ( void *p )
+{
+ /* We don't bother cleaning up the buffer table entries -
+ * we're hardly limited */
+ free_dma ( p, EFAB_BUF_ALIGN );
+}
+
+static void*
+falcon_alloc_special_buffer ( struct efab_nic *efab, int bytes,
+ struct efab_special_buffer *entry )
+{
+ void* buffer;
+ int remaining;
+ efab_qword_t buf_desc;
+ unsigned long dma_addr;
+
+ /* Allocate the buffer, aligned on a buffer address boundary */
+ buffer = malloc_dma ( bytes, EFAB_BUF_ALIGN );
+ if ( ! buffer )
+ return NULL;
+
+ /* Push buffer table entries to back the buffer */
+ entry->id = efab->buffer_head;
+ entry->dma_addr = dma_addr = virt_to_bus ( buffer );
+ assert ( ( dma_addr & ( EFAB_BUF_ALIGN - 1 ) ) == 0 );
+
+ remaining = bytes;
+ while ( remaining > 0 ) {
+ EFAB_POPULATE_QWORD_3 ( buf_desc,
+ FCN_IP_DAT_BUF_SIZE, FCN_IP_DAT_BUF_SIZE_4K,
+ FCN_BUF_ADR_FBUF, ( dma_addr >> 12 ),
+ FCN_BUF_OWNER_ID_FBUF, 0 );
+
+ falcon_write_sram ( efab, &buf_desc, efab->buffer_head );
+
+ ++efab->buffer_head;
+ dma_addr += EFAB_BUF_ALIGN;
+ remaining -= EFAB_BUF_ALIGN;
+ }
+
+ EFAB_TRACE ( "Allocated 0x%x bytes at %p backed by buffer table "
+ "entries 0x%x..0x%x\n", bytes, buffer, entry->id,
+ efab->buffer_head - 1 );
+
+ return buffer;
+}
- /* identify FPGA/ASIC, and strapping mode */
- falcon_read ( efab, &reg, ALTERA_BUILD_REG_KER );
- version = EFAB_OWORD_FIELD ( reg, VER_ALL );
- efab->is_asic = version ? 0 : 1;
+static void
+clear_b0_fpga_memories ( struct efab_nic *efab)
+{
+ efab_oword_t blanko, temp;
+ efab_dword_t blankd;
+ int offset;
+
+ EFAB_ZERO_OWORD ( blanko );
+ EFAB_ZERO_DWORD ( blankd );
+
+ /* Clear the address region register */
+ EFAB_POPULATE_OWORD_4 ( temp,
+ FCN_ADR_REGION0, 0,
+ FCN_ADR_REGION1, ( 1 << 16 ),
+ FCN_ADR_REGION2, ( 2 << 16 ),
+ FCN_ADR_REGION3, ( 3 << 16 ) );
+ falcon_write ( efab, &temp, FCN_ADR_REGION_REG_KER );
- if ( efab->is_asic ) {
- falcon_read ( efab, &reg, FCN_NIC_STAT_REG );
- if ( EFAB_OWORD_FIELD ( reg, STRAP_10G ) ) {
- efab->is_10g = 1;
- }
- if ( EFAB_OWORD_FIELD ( reg, STRAP_DUAL_PORT ) ) {
- efab->is_dual = 1;
- }
+ EFAB_TRACE ( "Clearing filter and RSS tables\n" );
+
+ for ( offset = FCN_RX_FILTER_TBL0 ;
+ offset < FCN_RX_RSS_INDIR_TBL_B0+0x800 ;
+ offset += 0x10 ) {
+ falcon_write ( efab, &blanko, offset );
+ }
+
+ EFAB_TRACE ( "Wiping buffer tables\n" );
+
+ /* Notice the 8 byte access mode */
+ for ( offset = 0x2800000 ;
+ offset < 0x3000000 ;
+ offset += 0x8) {
+ _falcon_writel ( efab, 0, offset );
+ _falcon_writel ( efab, 0, offset + 4 );
+ wmb();
+ }
+}
+
+static int
+falcon_reset ( struct efab_nic *efab )
+{
+ efab_oword_t glb_ctl_reg_ker;
+
+ /* Initiate software reset */
+ EFAB_POPULATE_OWORD_6 ( glb_ctl_reg_ker,
+ FCN_PCIE_CORE_RST_CTL, EXCLUDE_FROM_RESET,
+ FCN_PCIE_NSTCK_RST_CTL, EXCLUDE_FROM_RESET,
+ FCN_PCIE_SD_RST_CTL, EXCLUDE_FROM_RESET,
+ FCN_EE_RST_CTL, EXCLUDE_FROM_RESET,
+ FCN_EXT_PHY_RST_DUR, 0x7, /* 10ms */
+ FCN_SWRST, 1 );
+
+ falcon_write ( efab, &glb_ctl_reg_ker, FCN_GLB_CTL_REG_KER );
+
+ /* Allow 50ms for reset */
+ mdelay ( 50 );
+
+ /* Check for device reset complete */
+ falcon_read ( efab, &glb_ctl_reg_ker, FCN_GLB_CTL_REG_KER );
+ if ( EFAB_OWORD_FIELD ( glb_ctl_reg_ker, FCN_SWRST ) != 0 ) {
+ EFAB_ERR ( "Reset failed\n" );
+ return -ETIMEDOUT;
+ }
+
+ if ( ( efab->pci_revision == FALCON_REV_B0 ) && !efab->is_asic ) {
+ clear_b0_fpga_memories ( efab );
+ }
+
+ return 0;
+}
+
+/** Offset of MAC address within EEPROM or Flash */
+#define FALCON_MAC_ADDRESS_OFFSET 0x310
+
+/*
+ * Falcon EEPROM structure
+ */
+#define SF_NV_CONFIG_BASE 0x300
+#define SF_NV_CONFIG_EXTRA 0xA0
+
+struct falcon_nv_config_ver2 {
+ uint16_t nports;
+ uint8_t port0_phy_addr;
+ uint8_t port0_phy_type;
+ uint8_t port1_phy_addr;
+ uint8_t port1_phy_type;
+ uint16_t asic_sub_revision;
+ uint16_t board_revision;
+ uint8_t mac_location;
+};
+
+struct falcon_nv_extra {
+ uint16_t magicnumber;
+ uint16_t structure_version;
+ uint16_t checksum;
+ union {
+ struct falcon_nv_config_ver2 ver2;
+ } ver_specific;
+};
+
+#define BOARD_TYPE(_rev) (_rev >> 8)
+
+static void
+falcon_probe_nic_variant ( struct efab_nic *efab, struct pci_device *pci )
+{
+ efab_oword_t altera_build, nic_stat;
+ int is_pcie, fpga_version;
+ uint8_t revision;
+
+ /* PCI revision */
+ pci_read_config_byte ( pci, PCI_CLASS_REVISION, &revision );
+ efab->pci_revision = revision;
+
+ /* Asic vs FPGA */
+ falcon_read ( efab, &altera_build, FCN_ALTERA_BUILD_REG_KER );
+ fpga_version = EFAB_OWORD_FIELD ( altera_build, FCN_VER_ALL );
+ efab->is_asic = (fpga_version == 0);
+
+ /* MAC and PCI type */
+ falcon_read ( efab, &nic_stat, FCN_NIC_STAT_REG );
+ if ( efab->pci_revision == FALCON_REV_B0 ) {
+ is_pcie = 1;
+ efab->phy_10g = EFAB_OWORD_FIELD ( nic_stat, FCN_STRAP_10G );
+ }
+ else if ( efab->is_asic ) {
+ is_pcie = EFAB_OWORD_FIELD ( nic_stat, FCN_STRAP_PCIE );
+ efab->phy_10g = EFAB_OWORD_FIELD ( nic_stat, FCN_STRAP_10G );
}
else {
- falcon_read ( efab, &reg, ALTERA_BUILD_REG_KER );
- minor = EFAB_OWORD_FIELD ( reg, VER_MINOR );
+ int minor = EFAB_OWORD_FIELD ( altera_build, FCN_VER_MINOR );
+ is_pcie = 0;
+ efab->phy_10g = ( minor == 0x14 );
+ }
+}
+
+static void
+falcon_init_spi_device ( struct efab_nic *efab, struct spi_device *spi )
+{
+ /* Falcon's SPI interface only supports reads/writes of up to 16 bytes.
+ * Reduce the nvs block size down to satisfy this - which means callers
+ * should use the nvs_* functions rather than spi_*. */
+ if ( spi->nvs.block_size > FALCON_SPI_MAX_LEN )
+ spi->nvs.block_size = FALCON_SPI_MAX_LEN;
+
+ spi->bus = &efab->spi_bus;
+ efab->spi = spi;
+}
+
+static int
+falcon_probe_spi ( struct efab_nic *efab )
+{
+ efab_oword_t nic_stat, gpio_ctl, ee_vpd_cfg;
+ int has_flash, has_eeprom, ad9bit;
+
+ falcon_read ( efab, &nic_stat, FCN_NIC_STAT_REG );
+ falcon_read ( efab, &gpio_ctl, FCN_GPIO_CTL_REG_KER );
+ falcon_read ( efab, &ee_vpd_cfg, FCN_EE_VPD_CFG_REG );
+
+ /* determine if FLASH / EEPROM is present */
+ if ( ( efab->pci_revision >= FALCON_REV_B0 ) || efab->is_asic ) {
+ has_flash = EFAB_OWORD_FIELD ( nic_stat, FCN_SF_PRST );
+ has_eeprom = EFAB_OWORD_FIELD ( nic_stat, FCN_EE_PRST );
+ } else {
+ has_flash = EFAB_OWORD_FIELD ( gpio_ctl, FCN_FLASH_PRESENT );
+ has_eeprom = EFAB_OWORD_FIELD ( gpio_ctl, FCN_EEPROM_PRESENT );
+ }
+ ad9bit = EFAB_OWORD_FIELD ( ee_vpd_cfg, FCN_EE_VPD_EN_AD9_MODE );
+
+ /* Configure the SPI and I2C bus */
+ efab->spi_bus.rw = falcon_spi_rw;
+ init_i2c_bit_basher ( &efab->i2c_bb, &falcon_i2c_bit_ops );
+
+ /* Configure the EEPROM SPI device. Generally, an Atmel 25040
+ * (or similar) is used, but this is only possible if there is also
+ * a flash device present to store the boot-time chip configuration.
+ */
+ if ( has_eeprom ) {
+ if ( has_flash && ad9bit )
+ init_at25040 ( &efab->spi_eeprom );
+ else
+ init_mc25xx640 ( &efab->spi_eeprom );
+ falcon_init_spi_device ( efab, &efab->spi_eeprom );
+ }
+
+ /* Configure the FLASH SPI device */
+ if ( has_flash ) {
+ init_at25f1024 ( &efab->spi_flash );
+ falcon_init_spi_device ( efab, &efab->spi_flash );
+ }
+
+ EFAB_LOG ( "flash is %s, EEPROM is %s%s\n",
+ ( has_flash ? "present" : "absent" ),
+ ( has_eeprom ? "present " : "absent" ),
+ ( has_eeprom ? (ad9bit ? "(9bit)" : "(16bit)") : "") );
+
+ /* The device MUST have flash or eeprom */
+ if ( ! efab->spi ) {
+ EFAB_ERR ( "Device appears to have no flash or eeprom\n" );
+ return -EIO;
+ }
+
+ /* If the device has EEPROM attached, then advertise NVO space */
+ if ( has_eeprom )
+ nvo_init ( &efab->nvo, &efab->spi_eeprom.nvs, falcon_nvo_fragments,
+ &efab->netdev->refcnt );
+
+ return 0;
+}
+
+static int
+falcon_probe_nvram ( struct efab_nic *efab )
+{
+ struct nvs_device *nvs = &efab->spi->nvs;
+ struct falcon_nv_extra nv;
+ int rc, board_revision;
+
+ /* Read the MAC address */
+ rc = nvs_read ( nvs, FALCON_MAC_ADDRESS_OFFSET,
+ efab->mac_addr, ETH_ALEN );
+ if ( rc )
+ return rc;
+
+ /* Poke through the NVRAM structure for the PHY type. */
+ rc = nvs_read ( nvs, SF_NV_CONFIG_BASE + SF_NV_CONFIG_EXTRA,
+ &nv, sizeof ( nv ) );
+ if ( rc )
+ return rc;
+
+ /* Handle each supported NVRAM version */
+ if ( ( le16_to_cpu ( nv.magicnumber ) == FCN_NV_MAGIC_NUMBER ) &&
+ ( le16_to_cpu ( nv.structure_version ) >= 2 ) ) {
+ struct falcon_nv_config_ver2* ver2 = &nv.ver_specific.ver2;
- if ( minor == 0x14 ) {
- efab->is_10g = 1;
- } else if ( minor == 0x13 ) {
- efab->is_dual = 1;
- }
+ /* Get the PHY type */
+ efab->phy_addr = le16_to_cpu ( ver2->port0_phy_addr );
+ efab->phy_type = le16_to_cpu ( ver2->port0_phy_type );
+ board_revision = le16_to_cpu ( ver2->board_revision );
+ }
+ else {
+ EFAB_ERR ( "NVram is not recognised\n" );
+ return -EINVAL;
}
- DBG ( "NIC type: %s %dx%s\n",
- efab->is_asic ? "ASIC" : "FPGA",
- efab->is_dual ? 2 : 1,
- efab->is_10g ? "10G" : "1G" );
+ efab->board_type = BOARD_TYPE ( board_revision );
+
+ EFAB_TRACE ( "Falcon board %d phy %d @ addr %d\n",
+ efab->board_type, efab->phy_type, efab->phy_addr );
- /* patch in MAC operations */
- if ( efab->is_10g )
+ /* Patch in the board operations */
+ switch ( efab->board_type ) {
+ case EFAB_BOARD_SFE4001:
+ efab->board_op = &sfe4001_ops;
+ break;
+ case EFAB_BOARD_SFE4002:
+ efab->board_op = &sfe4002_ops;
+ break;
+ case EFAB_BOARD_SFE4003:
+ efab->board_op = &sfe4003_ops;
+ break;
+ default:
+ EFAB_ERR ( "Unrecognised board type\n" );
+ return -EINVAL;
+ }
+
+ /* Patch in MAC operations */
+ if ( efab->phy_10g )
efab->mac_op = &falcon_xmac_operations;
else
efab->mac_op = &falcon_gmac_operations;
-
- if ( !efab->is_dual && ( efab->port == 1 ) ) {
- /* device doesn't exist */
- return 0;
- }
- /* determine EEPROM / FLASH */
- if ( efab->is_asic ) {
- falcon_read ( efab, &reg, FCN_NIC_STAT_REG );
- efab->has_flash = EFAB_OWORD_FIELD ( reg, SF_PRST );
- efab->has_eeprom = EFAB_OWORD_FIELD ( reg, EE_PRST );
- } else {
- falcon_read ( efab, &reg, FCN_GPIO_CTL_REG_KER );
- efab->has_flash = EFAB_OWORD_FIELD ( reg, FCN_FLASH_PRESENT );
- efab->has_eeprom = EFAB_OWORD_FIELD ( reg, FCN_EEPROM_PRESENT);
+ /* Hook in the PHY ops */
+ switch ( efab->phy_type ) {
+ case PHY_TYPE_10XPRESS:
+ efab->phy_op = &falcon_tenxpress_phy_ops;
+ break;
+ case PHY_TYPE_CX4:
+ efab->phy_op = &falcon_xaui_phy_ops;
+ break;
+ case PHY_TYPE_XFP:
+ efab->phy_op = &falcon_xfp_phy_ops;
+ break;
+ case PHY_TYPE_CX4_RTMR:
+ efab->phy_op = &falcon_txc_phy_ops;
+ break;
+ case PHY_TYPE_PM8358:
+ efab->phy_op = &falcon_pm8358_phy_ops;
+ break;
+ case PHY_TYPE_1GIG_ALASKA:
+ efab->phy_op = &falcon_alaska_phy_ops;
+ break;
+ default:
+ EFAB_ERR ( "Unknown PHY type: %d\n", efab->phy_type );
+ return -EINVAL;
}
- DBG ( "flash is %s, EEPROM is %s\n",
- ( efab->has_flash ? "present" : "absent" ),
- ( efab->has_eeprom ? "present" : "absent" ) );
- falcon_init_spi ( efab );
+ return 0;
+}
+
+static int
+falcon_init_sram ( struct efab_nic *efab )
+{
+ efab_oword_t reg;
+ int count;
+
+ /* use card in internal SRAM mode */
+ falcon_read ( efab, &reg, FCN_NIC_STAT_REG );
+ EFAB_SET_OWORD_FIELD ( reg, FCN_ONCHIP_SRAM, 1 );
+ falcon_write ( efab, &reg, FCN_NIC_STAT_REG );
+
+ /* Deactivate any external SRAM that might be present */
+ EFAB_POPULATE_OWORD_2 ( reg,
+ FCN_GPIO1_OEN, 1,
+ FCN_GPIO1_OUT, 1 );
+ falcon_write ( efab, &reg, FCN_GPIO_CTL_REG_KER );
+
+ /* Initiate SRAM reset */
+ EFAB_POPULATE_OWORD_2 ( reg,
+ FCN_SRAM_OOB_BT_INIT_EN, 1,
+ FCN_SRM_NUM_BANKS_AND_BANK_SIZE, 0 );
+ falcon_write ( efab, &reg, FCN_SRM_CFG_REG_KER );
+
+ /* Wait for SRAM reset to complete */
+ count = 0;
+ do {
+ /* SRAM reset is slow; expect around 16ms */
+ mdelay ( 20 );
+
+ /* Check for reset complete */
+ falcon_read ( efab, &reg, FCN_SRM_CFG_REG_KER );
+ if ( !EFAB_OWORD_FIELD ( reg, FCN_SRAM_OOB_BT_INIT_EN ) )
+ return 0;
+ } while (++count < 20); /* wait upto 0.4 sec */
+
+ EFAB_ERR ( "timed out waiting for SRAM reset\n");
+ return -ETIMEDOUT;
+}
+
+static void
+falcon_setup_nic ( struct efab_nic *efab )
+{
+ efab_dword_t timer_cmd;
+ efab_oword_t reg;
+ int tx_fc, xoff_thresh, xon_thresh;
+
+ /* bug5129: Clear the parity enables on the TX data fifos as
+ * they produce false parity errors because of timing issues
+ */
+ falcon_read ( efab, &reg, FCN_SPARE_REG_KER );
+ EFAB_SET_OWORD_FIELD ( reg, FCN_MEM_PERR_EN_TX_DATA, 0 );
+ falcon_write ( efab, &reg, FCN_SPARE_REG_KER );
+
/* Set up TX and RX descriptor caches in SRAM */
- EFAB_POPULATE_OWORD_1 ( reg, FCN_SRM_TX_DC_BASE_ADR,
- 0x130000 /* recommended in datasheet */ );
+ EFAB_POPULATE_OWORD_1 ( reg, FCN_SRM_TX_DC_BASE_ADR, 0x130000 );
falcon_write ( efab, &reg, FCN_SRM_TX_DC_CFG_REG_KER );
- EFAB_POPULATE_OWORD_1 ( reg, FCN_TX_DC_SIZE, 2 /* 32 descriptors */ );
+ EFAB_POPULATE_OWORD_1 ( reg, FCN_TX_DC_SIZE, 1 /* 16 descriptors */ );
falcon_write ( efab, &reg, FCN_TX_DC_CFG_REG_KER );
- EFAB_POPULATE_OWORD_1 ( reg, FCN_SRM_RX_DC_BASE_ADR,
- 0x100000 /* recommended in datasheet */ );
+ EFAB_POPULATE_OWORD_1 ( reg, FCN_SRM_RX_DC_BASE_ADR, 0x100000 );
falcon_write ( efab, &reg, FCN_SRM_RX_DC_CFG_REG_KER );
EFAB_POPULATE_OWORD_1 ( reg, FCN_RX_DC_SIZE, 2 /* 32 descriptors */ );
falcon_write ( efab, &reg, FCN_RX_DC_CFG_REG_KER );
- /* Set number of RSS CPUs */
- EFAB_POPULATE_OWORD_1 ( reg, FCN_NUM_KER, 0 );
+ /* Set number of RSS CPUs
+ * bug7244: Increase filter depth to reduce RX_RESET likelyhood
+ */
+ EFAB_POPULATE_OWORD_5 ( reg,
+ FCN_NUM_KER, 0,
+ FCN_UDP_FULL_SRCH_LIMIT, 8,
+ FCN_UDP_WILD_SRCH_LIMIT, 8,
+ FCN_TCP_WILD_SRCH_LIMIT, 8,
+ FCN_TCP_FULL_SRCH_LIMIT, 8);
falcon_write ( efab, &reg, FCN_RX_FILTER_CTL_REG_KER );
udelay ( 1000 );
+
+ /* Setup RX. Wait for descriptor is broken and must
+ * be disabled. RXDP recovery shouldn't be needed, but is.
+ * disable ISCSI parsing because we don't need it
+ */
+ falcon_read ( efab, &reg, FCN_RX_SELF_RST_REG_KER );
+ EFAB_SET_OWORD_FIELD ( reg, FCN_RX_NODESC_WAIT_DIS, 1 );
+ EFAB_SET_OWORD_FIELD ( reg, FCN_RX_RECOVERY_EN, 1 );
+ EFAB_SET_OWORD_FIELD ( reg, FCN_RX_ISCSI_DIS, 1 );
+ falcon_write ( efab, &reg, FCN_RX_SELF_RST_REG_KER );
- /* Reset the MAC */
- mentormac_reset ( efab );
+ /* Determine recommended flow control settings. *
+ * Flow control is qualified on B0 and A1/1G, not on A1/10G */
+ if ( efab->pci_revision == FALCON_REV_B0 ) {
+ tx_fc = 1;
+ xoff_thresh = 54272; /* ~80Kb - 3*max MTU */
+ xon_thresh = 27648; /* ~3*max MTU */
+ }
+ else if ( !efab->phy_10g ) {
+ tx_fc = 1;
+ xoff_thresh = 2048;
+ xon_thresh = 512;
+ }
+ else {
+ tx_fc = xoff_thresh = xon_thresh = 0;
+ }
- /* Set up event queue */
- falcon_create_special_buffer ( efab, efab->eventq, FALCON_EVQ_ID );
- /* Fill eventq with all ones ( empty events ) */
- memset(efab->eventq, 0xff, 4096);
- /* push eventq to card */
- EFAB_POPULATE_OWORD_3 ( reg,
- FCN_EVQ_EN, 1,
- FCN_EVQ_SIZE, FCN_EVQ_SIZE_512,
- FCN_EVQ_BUF_BASE_ID, FALCON_EVQ_ID );
- falcon_write ( efab, &reg, FCN_EVQ_PTR_TBL_KER );
- udelay ( 1000 );
+ /* Setup TX and RX */
+ falcon_read ( efab, &reg, FCN_TX_CFG2_REG_KER );
+ EFAB_SET_OWORD_FIELD ( reg, FCN_TX_DIS_NON_IP_EV, 1 );
+ falcon_write ( efab, &reg, FCN_TX_CFG2_REG_KER );
+
+ falcon_read ( efab, &reg, FCN_RX_CFG_REG_KER );
+ EFAB_SET_OWORD_FIELD_VER ( efab, reg, FCN_RX_USR_BUF_SIZE,
+ (3*4096) / 32 );
+ if ( efab->pci_revision == FALCON_REV_B0)
+ EFAB_SET_OWORD_FIELD ( reg, FCN_RX_INGR_EN_B0, 1 );
+ EFAB_SET_OWORD_FIELD_VER ( efab, reg, FCN_RX_XON_MAC_TH,
+ xon_thresh / 256);
+ EFAB_SET_OWORD_FIELD_VER ( efab, reg, FCN_RX_XOFF_MAC_TH,
+ xoff_thresh / 256);
+ EFAB_SET_OWORD_FIELD_VER ( efab, reg, FCN_RX_XOFF_MAC_EN, tx_fc);
+ falcon_write ( efab, &reg, FCN_RX_CFG_REG_KER );
/* Set timer register */
EFAB_POPULATE_DWORD_2 ( timer_cmd,
FCN_TIMER_MODE, FCN_TIMER_MODE_DIS,
FCN_TIMER_VAL, 0 );
falcon_writel ( efab, &timer_cmd, FCN_TIMER_CMD_REG_KER );
- udelay ( 1000 );
+}
+
+static void
+falcon_init_resources ( struct efab_nic *efab )
+{
+ struct efab_ev_queue *ev_queue = &efab->ev_queue;
+ struct efab_rx_queue *rx_queue = &efab->rx_queue;
+ struct efab_tx_queue *tx_queue = &efab->tx_queue;
- /* Initialise event queue read pointer */
- falcon_eventq_read_ack ( efab );
+ efab_oword_t reg;
+ int jumbo;
+
+ /* Initialise the ptrs */
+ tx_queue->read_ptr = tx_queue->write_ptr = 0;
+ rx_queue->read_ptr = rx_queue->write_ptr = 0;
+ ev_queue->read_ptr = 0;
+
+ /* Push the event queue to the hardware */
+ EFAB_POPULATE_OWORD_3 ( reg,
+ FCN_EVQ_EN, 1,
+ FCN_EVQ_SIZE, FQS(FCN_EVQ, EFAB_EVQ_SIZE),
+ FCN_EVQ_BUF_BASE_ID, ev_queue->entry.id );
+ falcon_write ( efab, &reg,
+ FCN_REVISION_REG ( efab, FCN_EVQ_PTR_TBL_KER ) );
- /* Set up TX descriptor ring */
- falcon_create_special_buffer ( efab, efab->txd, FALCON_TXD_ID );
- EFAB_POPULATE_OWORD_5 ( reg,
+ /* Push the tx queue to the hardware */
+ EFAB_POPULATE_OWORD_8 ( reg,
FCN_TX_DESCQ_EN, 1,
- FCN_TX_DESCQ_BUF_BASE_ID, FALCON_TXD_ID,
+ FCN_TX_ISCSI_DDIG_EN, 0,
+ FCN_TX_ISCSI_DDIG_EN, 0,
+ FCN_TX_DESCQ_BUF_BASE_ID, tx_queue->entry.id,
FCN_TX_DESCQ_EVQ_ID, 0,
- FCN_TX_DESCQ_SIZE, FCN_TX_DESCQ_SIZE_512,
- FCN_TX_DESCQ_TYPE, 0 /* kernel queue */ );
- falcon_write ( efab, &reg, FCN_TX_DESC_PTR_TBL_KER );
-
- /* Set up RX descriptor ring */
- falcon_create_special_buffer ( efab, efab->rxd, FALCON_RXD_ID );
- EFAB_POPULATE_OWORD_6 ( reg,
- FCN_RX_DESCQ_BUF_BASE_ID, FALCON_RXD_ID,
+ FCN_TX_DESCQ_SIZE, FQS(FCN_TX_DESCQ, EFAB_TXD_SIZE),
+ FCN_TX_DESCQ_TYPE, 0 /* kernel queue */,
+ FCN_TX_NON_IP_DROP_DIS_B0, 1 );
+ falcon_write ( efab, &reg,
+ FCN_REVISION_REG ( efab, FCN_TX_DESC_PTR_TBL_KER ) );
+
+ /* Push the rx queue to the hardware */
+ jumbo = ( efab->pci_revision == FALCON_REV_B0 ) ? 0 : 1;
+ EFAB_POPULATE_OWORD_8 ( reg,
+ FCN_RX_ISCSI_DDIG_EN, 0,
+ FCN_RX_ISCSI_HDIG_EN, 0,
+ FCN_RX_DESCQ_BUF_BASE_ID, rx_queue->entry.id,
FCN_RX_DESCQ_EVQ_ID, 0,
- FCN_RX_DESCQ_SIZE, FCN_RX_DESCQ_SIZE_512,
+ FCN_RX_DESCQ_SIZE, FQS(FCN_RX_DESCQ, EFAB_RXD_SIZE),
FCN_RX_DESCQ_TYPE, 0 /* kernel queue */,
- FCN_RX_DESCQ_JUMBO, 1,
+ FCN_RX_DESCQ_JUMBO, jumbo,
FCN_RX_DESCQ_EN, 1 );
- falcon_write ( efab, &reg, FCN_RX_DESC_PTR_TBL_KER );
+ falcon_write ( efab, &reg,
+ FCN_REVISION_REG ( efab, FCN_RX_DESC_PTR_TBL_KER ) );
/* Program INT_ADR_REG_KER */
EFAB_POPULATE_OWORD_1 ( reg,
- FCN_INT_ADR_KER,
- virt_to_bus ( &efab->int_ker ) );
+ FCN_INT_ADR_KER, virt_to_bus ( &efab->int_ker ) );
falcon_write ( efab, &reg, FCN_INT_ADR_REG_KER );
- udelay ( 1000 );
- /* Register non-volatile storage */
- if ( efab->has_eeprom ) {
- nvo_init ( &efab->nvo, &efab->falcon_eeprom.nvs,
- falcon_eeprom_fragments, NULL /* hack */ );
- if ( register_nvo ( &efab->nvo, NULL /* hack */ ) != 0 )
- return 0;
- }
+ /* Ack the event queue */
+ falcon_eventq_read_ack ( efab, ev_queue );
+}
- return 1;
+static void
+falcon_fini_resources ( struct efab_nic *efab )
+{
+ efab_oword_t cmd;
+
+ /* Disable interrupts */
+ falcon_interrupts ( efab, 0, 0 );
+
+ /* Flush the dma queues */
+ EFAB_POPULATE_OWORD_2 ( cmd,
+ FCN_TX_FLUSH_DESCQ_CMD, 1,
+ FCN_TX_FLUSH_DESCQ, 0 );
+ falcon_write ( efab, &cmd,
+ FCN_REVISION_REG ( efab, FCN_TX_DESC_PTR_TBL_KER ) );
+
+ EFAB_POPULATE_OWORD_2 ( cmd,
+ FCN_RX_FLUSH_DESCQ_CMD, 1,
+ FCN_RX_FLUSH_DESCQ, 0 );
+ falcon_write ( efab, &cmd,
+ FCN_REVISION_REG ( efab, FCN_RX_DESC_PTR_TBL_KER ) );
+
+ mdelay ( 100 );
+
+ /* Remove descriptor rings from card */
+ EFAB_ZERO_OWORD ( cmd );
+ falcon_write ( efab, &cmd,
+ FCN_REVISION_REG ( efab, FCN_TX_DESC_PTR_TBL_KER ) );
+ falcon_write ( efab, &cmd,
+ FCN_REVISION_REG ( efab, FCN_RX_DESC_PTR_TBL_KER ) );
+ falcon_write ( efab, &cmd,
+ FCN_REVISION_REG ( efab, FCN_EVQ_PTR_TBL_KER ) );
}
-/** MDIO write */
-static void falcon_mdio_write ( struct efab_nic *efab, int location,
- int value ) {
- int phy_id = efab->port + 2;
- efab_oword_t reg;
+/*******************************************************************************
+ *
+ *
+ * Hardware rx path
+ *
+ *
+ *******************************************************************************/
- EFAB_TRACE ( "Writing GMII %d register %02x with %04x\n",
- phy_id, location, value );
+static void
+falcon_build_rx_desc ( falcon_rx_desc_t *rxd, struct io_buffer *iob )
+{
+ EFAB_POPULATE_QWORD_2 ( *rxd,
+ FCN_RX_KER_BUF_SIZE, EFAB_RX_BUF_SIZE,
+ FCN_RX_KER_BUF_ADR, virt_to_bus ( iob->data ) );
+}
- /* Check MII not currently being accessed */
- if ( ! falcon_gmii_wait ( efab ) )
- return;
+static void
+falcon_notify_rx_desc ( struct efab_nic *efab, struct efab_rx_queue *rx_queue )
+{
+ efab_dword_t reg;
+ int ptr = rx_queue->write_ptr % EFAB_RXD_SIZE;
- /* Write the address registers */
- EFAB_POPULATE_OWORD_1 ( reg, FCN_MD_PHY_ADR, 0 /* phy_id ? */ );
- falcon_write ( efab, &reg, FCN_MD_PHY_ADR_REG_KER );
- udelay ( 10 );
- EFAB_POPULATE_OWORD_2 ( reg,
- FCN_MD_PRT_ADR, phy_id,
- FCN_MD_DEV_ADR, location );
- falcon_write ( efab, &reg, FCN_MD_ID_REG_KER );
- udelay ( 10 );
+ EFAB_POPULATE_DWORD_1 ( reg, FCN_RX_DESC_WPTR_DWORD, ptr );
+ falcon_writel ( efab, &reg, FCN_RX_DESC_UPD_REG_KER_DWORD );
+}
- /* Write data */
- EFAB_POPULATE_OWORD_1 ( reg, FCN_MD_TXD, value );
- falcon_write ( efab, &reg, FCN_MD_TXD_REG_KER );
- udelay ( 10 );
- EFAB_POPULATE_OWORD_2 ( reg,
- FCN_MD_WRC, 1,
- FCN_MD_GC, 1 );
- falcon_write ( efab, &reg, FCN_MD_CS_REG_KER );
- udelay ( 10 );
-
- /* Wait for data to be written */
- falcon_gmii_wait ( efab );
+
+/*******************************************************************************
+ *
+ *
+ * Hardware tx path
+ *
+ *
+ *******************************************************************************/
+
+static void
+falcon_build_tx_desc ( falcon_tx_desc_t *txd, struct io_buffer *iob )
+{
+ EFAB_POPULATE_QWORD_2 ( *txd,
+ FCN_TX_KER_BYTE_CNT, iob_len ( iob ),
+ FCN_TX_KER_BUF_ADR, virt_to_bus ( iob->data ) );
}
-/** MDIO read */
-static int falcon_mdio_read ( struct efab_nic *efab, int location ) {
- int phy_id = efab->port + 2;
- efab_oword_t reg;
- int value;
+static void
+falcon_notify_tx_desc ( struct efab_nic *efab,
+ struct efab_tx_queue *tx_queue )
+{
+ efab_dword_t reg;
+ int ptr = tx_queue->write_ptr % EFAB_TXD_SIZE;
- /* Check MII not currently being accessed */
- if ( ! falcon_gmii_wait ( efab ) )
- return 0xffff;
+ EFAB_POPULATE_DWORD_1 ( reg, FCN_TX_DESC_WPTR_DWORD, ptr );
+ falcon_writel ( efab, &reg, FCN_TX_DESC_UPD_REG_KER_DWORD );
+}
- /* Write the address registers */
- EFAB_POPULATE_OWORD_1 ( reg, FCN_MD_PHY_ADR, 0 /* phy_id ? */ );
- falcon_write ( efab, &reg, FCN_MD_PHY_ADR_REG_KER );
- udelay ( 10 );
- EFAB_POPULATE_OWORD_2 ( reg,
- FCN_MD_PRT_ADR, phy_id,
- FCN_MD_DEV_ADR, location );
- falcon_write ( efab, &reg, FCN_MD_ID_REG_KER );
- udelay ( 10 );
- /* Request data to be read */
- EFAB_POPULATE_OWORD_2 ( reg,
- FCN_MD_RIC, 1,
- FCN_MD_GC, 1 );
- falcon_write ( efab, &reg, FCN_MD_CS_REG_KER );
- udelay ( 10 );
-
- /* Wait for data to become available */
- falcon_gmii_wait ( efab );
+/*******************************************************************************
+ *
+ *
+ * Software receive interface
+ *
+ *
+ *******************************************************************************/
- /* Read the data */
- falcon_read ( efab, &reg, FCN_MD_RXD_REG_KER );
- value = EFAB_OWORD_FIELD ( reg, FCN_MD_RXD );
+static int
+efab_fill_rx_queue ( struct efab_nic *efab,
+ struct efab_rx_queue *rx_queue )
+{
+ int fill_level = rx_queue->write_ptr - rx_queue->read_ptr;
+ int space = EFAB_NUM_RX_DESC - fill_level - 1;
+ int pushed = 0;
+
+ while ( space ) {
+ int buf_id = rx_queue->write_ptr % EFAB_NUM_RX_DESC;
+ int desc_id = rx_queue->write_ptr % EFAB_RXD_SIZE;
+ struct io_buffer *iob;
+ falcon_rx_desc_t *rxd;
+
+ assert ( rx_queue->buf[buf_id] == NULL );
+ iob = alloc_iob ( EFAB_RX_BUF_SIZE );
+ if ( !iob )
+ break;
- EFAB_TRACE ( "Read from GMII %d register %02x, got %04x\n",
- phy_id, location, value );
+ EFAB_TRACE ( "pushing rx_buf[%d] iob %p data %p\n",
+ buf_id, iob, iob->data );
- return value;
+ rx_queue->buf[buf_id] = iob;
+ rxd = rx_queue->ring + desc_id;
+ falcon_build_rx_desc ( rxd, iob );
+ ++rx_queue->write_ptr;
+ ++pushed;
+ --space;
+ }
+
+ if ( pushed ) {
+ /* Push the ptr to hardware */
+ falcon_notify_rx_desc ( efab, rx_queue );
+
+ fill_level = rx_queue->write_ptr - rx_queue->read_ptr;
+ EFAB_TRACE ( "pushed %d rx buffers to fill level %d\n",
+ pushed, fill_level );
+ }
+
+ if ( fill_level == 0 )
+ return -ENOMEM;
+ return 0;
}
+
+static void
+efab_receive ( struct efab_nic *efab, unsigned int id, int len, int drop )
+{
+ struct efab_rx_queue *rx_queue = &efab->rx_queue;
+ struct io_buffer *iob;
+ unsigned int read_ptr = rx_queue->read_ptr % EFAB_RXD_SIZE;
+ unsigned int buf_ptr = rx_queue->read_ptr % EFAB_NUM_RX_DESC;
-static struct efab_operations falcon_operations = {
- .get_membase = falcon_get_membase,
- .reset = falcon_reset,
- .init_nic = falcon_init_nic,
- .read_eeprom = falcon_read_eeprom,
- .build_rx_desc = falcon_build_rx_desc,
- .notify_rx_desc = falcon_notify_rx_desc,
- .build_tx_desc = falcon_build_tx_desc,
- .notify_tx_desc = falcon_notify_tx_desc,
- .fetch_event = falcon_fetch_event,
- .mask_irq = falcon_mask_irq,
- .generate_irq = falcon_generate_irq,
- .mdio_write = falcon_mdio_write,
- .mdio_read = falcon_mdio_read,
-};
+ assert ( id == read_ptr );
+
+ /* Pop this rx buffer out of the software ring */
+ iob = rx_queue->buf[buf_ptr];
+ rx_queue->buf[buf_ptr] = NULL;
-/**************************************************************************
+ EFAB_TRACE ( "popping rx_buf[%d] iob %p data %p with %d bytes %s\n",
+ id, iob, iob->data, len, drop ? "bad" : "ok" );
+
+ /* Pass the packet up if required */
+ if ( drop )
+ free_iob ( iob );
+ else {
+ iob_put ( iob, len );
+ netdev_rx ( efab->netdev, iob );
+ }
+
+ ++rx_queue->read_ptr;
+}
+
+/*******************************************************************************
*
- * Etherfabric abstraction layer
*
- **************************************************************************
- */
-
-/**
- * Push RX buffer to RXD ring
+ * Software transmit interface
*
- */
-static inline void efab_push_rx_buffer ( struct efab_nic *efab,
- struct efab_rx_buf *rx_buf ) {
- /* Create RX descriptor */
- rx_buf->id = efab->rx_write_ptr;
- efab->op->build_rx_desc ( efab, rx_buf );
+ *
+ *******************************************************************************/
- /* Update RX write pointer */
- efab->rx_write_ptr = ( efab->rx_write_ptr + 1 ) % EFAB_RXD_SIZE;
- efab->op->notify_rx_desc ( efab );
+static int
+efab_transmit ( struct net_device *netdev, struct io_buffer *iob )
+{
+ struct efab_nic *efab = netdev_priv ( netdev );
+ struct efab_tx_queue *tx_queue = &efab->tx_queue;
+ int fill_level, space;
+ falcon_tx_desc_t *txd;
+ int buf_id;
+
+ fill_level = tx_queue->write_ptr - tx_queue->read_ptr;
+ space = EFAB_TXD_SIZE - fill_level - 1;
+ if ( space < 1 )
+ return -ENOBUFS;
+
+ /* Save the iobuffer for later completion */
+ buf_id = tx_queue->write_ptr % EFAB_TXD_SIZE;
+ assert ( tx_queue->buf[buf_id] == NULL );
+ tx_queue->buf[buf_id] = iob;
+
+ EFAB_TRACE ( "tx_buf[%d] for iob %p data %p len %d\n",
+ buf_id, iob, iob->data, iob_len ( iob ) );
+
+ /* Form the descriptor, and push it to hardware */
+ txd = tx_queue->ring + buf_id;
+ falcon_build_tx_desc ( txd, iob );
+ ++tx_queue->write_ptr;
+ falcon_notify_tx_desc ( efab, tx_queue );
- DBG ( "Added RX id %x\n", rx_buf->id );
+ return 0;
}
-/**
- * Push TX buffer to TXD ring
- *
- */
-static inline void efab_push_tx_buffer ( struct efab_nic *efab,
- struct efab_tx_buf *tx_buf ) {
- /* Create TX descriptor */
- tx_buf->id = efab->tx_write_ptr;
- efab->op->build_tx_desc ( efab, tx_buf );
+static int
+efab_transmit_done ( struct efab_nic *efab, int id )
+{
+ struct efab_tx_queue *tx_queue = &efab->tx_queue;
+ unsigned int read_ptr, stop;
+
+ /* Complete all buffers from read_ptr up to and including id */
+ read_ptr = tx_queue->read_ptr % EFAB_TXD_SIZE;
+ stop = ( id + 1 ) % EFAB_TXD_SIZE;
- /* Update TX write pointer */
- efab->tx_write_ptr = ( efab->tx_write_ptr + 1 ) % EFAB_TXD_SIZE;
- efab->op->notify_tx_desc ( efab );
+ while ( read_ptr != stop ) {
+ struct io_buffer *iob = tx_queue->buf[read_ptr];
+ assert ( iob );
- DBG ( "Added TX id %x\n", tx_buf->id );
+ /* Complete the tx buffer */
+ if ( iob )
+ netdev_tx_complete ( efab->netdev, iob );
+ tx_queue->buf[read_ptr] = NULL;
+
+ ++tx_queue->read_ptr;
+ read_ptr = tx_queue->read_ptr % EFAB_TXD_SIZE;
+ }
+
+ return 0;
}
-/**
- * Initialise MAC and wait for link up
+/*******************************************************************************
*
- */
-static int efab_init_mac ( struct efab_nic *efab ) {
- int count;
+ *
+ * Hardware event path
+ *
+ *
+ *******************************************************************************/
- /* This can take several seconds */
- EFAB_LOG ( "Waiting for link.." );
- for ( count=0; count<5; count++ ) {
- putchar ( '.' );
+static void
+falcon_clear_interrupts ( struct efab_nic *efab )
+{
+ efab_dword_t reg;
- if ( ! efab->mac_op->init ( efab ) ) {
- EFAB_ERR ( "Failed reinitialising MAC\n" );
- return 0;
- }
- if ( efab->link_up ) {
- /* PHY init printed the message for us */
- return 1;
- }
- EFAB_ERR( "link is down" );
- sleep ( 1 );
+ if ( efab->pci_revision == FALCON_REV_B0 ) {
+ /* read the ISR */
+ falcon_readl( efab, &reg, INT_ISR0_B0 );
+ }
+ else {
+ /* write to the INT_ACK register */
+ falcon_writel ( efab, 0, FCN_INT_ACK_KER_REG_A1 );
+ mb();
+ falcon_readl ( efab, &reg,
+ WORK_AROUND_BROKEN_PCI_READS_REG_KER_A1 );
}
- EFAB_ERR ( " timed initialising MAC\n " );
+}
- return 0;
+static void
+falcon_handle_event ( struct efab_nic *efab, falcon_event_t *evt )
+{
+ int ev_code, desc_ptr, len, drop;
+
+ /* Decode event */
+ ev_code = EFAB_QWORD_FIELD ( *evt, FCN_EV_CODE );
+ switch ( ev_code ) {
+ case FCN_TX_IP_EV_DECODE:
+ desc_ptr = EFAB_QWORD_FIELD ( *evt, FCN_TX_EV_DESC_PTR );
+ efab_transmit_done ( efab, desc_ptr );
+ break;
+
+ case FCN_RX_IP_EV_DECODE:
+ desc_ptr = EFAB_QWORD_FIELD ( *evt, FCN_RX_EV_DESC_PTR );
+ len = EFAB_QWORD_FIELD ( *evt, FCN_RX_EV_BYTE_CNT );
+ drop = !EFAB_QWORD_FIELD ( *evt, FCN_RX_EV_PKT_OK );
+
+ efab_receive ( efab, desc_ptr, len, drop );
+ break;
+
+ default:
+ EFAB_TRACE ( "Unknown event type %d\n", ev_code );
+ break;
+ }
}
-/**
- * Initialise NIC
+/*******************************************************************************
*
- */
-static int efab_init_nic ( struct efab_nic *efab ) {
- int i;
+ *
+ * Software (polling) interrupt handler
+ *
+ *
+ *******************************************************************************/
- /* Initialise NIC */
- if ( ! efab->op->init_nic ( efab ) )
- return 0;
+static void
+efab_poll ( struct net_device *netdev )
+{
+ struct efab_nic *efab = netdev_priv ( netdev );
+ struct efab_ev_queue *ev_queue = &efab->ev_queue;
+ struct efab_rx_queue *rx_queue = &efab->rx_queue;
+ falcon_event_t *evt;
- /* Push RX descriptors */
- for ( i = 0 ; i < EFAB_RX_BUFS ; i++ ) {
- efab_push_rx_buffer ( efab, &efab->rx_bufs[i] );
+ /* Read the event queue by directly looking for events
+ * (we don't even bother to read the eventq write ptr) */
+ evt = ev_queue->ring + ev_queue->read_ptr;
+ while ( falcon_event_present ( evt ) ) {
+
+ EFAB_TRACE ( "Event at index 0x%x address %p is "
+ EFAB_QWORD_FMT "\n", ev_queue->read_ptr,
+ evt, EFAB_QWORD_VAL ( *evt ) );
+
+ falcon_handle_event ( efab, evt );
+
+ /* Clear the event */
+ EFAB_SET_QWORD ( *evt );
+
+ /* Move to the next event. We don't ack the event
+ * queue until the end */
+ ev_queue->read_ptr = ( ( ev_queue->read_ptr + 1 ) %
+ EFAB_EVQ_SIZE );
+ evt = ev_queue->ring + ev_queue->read_ptr;
}
- /* Read MAC address from EEPROM */
- if ( ! efab->op->read_eeprom ( efab ) )
- return 0;
+ /* Push more buffers if needed */
+ (void) efab_fill_rx_queue ( efab, rx_queue );
- /* Initialise MAC and wait for link up */
- if ( ! efab_init_mac ( efab ) )
- return 0;
+ /* Clear any pending interrupts */
+ falcon_clear_interrupts ( efab );
- return 1;
+ /* Ack the event queue */
+ falcon_eventq_read_ack ( efab, ev_queue );
}
-/**************************************************************************
+static void
+efab_irq ( struct net_device *netdev, int enable )
+{
+ struct efab_nic *efab = netdev_priv ( netdev );
+ struct efab_ev_queue *ev_queue = &efab->ev_queue;
+
+ switch ( enable ) {
+ case 0:
+ falcon_interrupts ( efab, 0, 0 );
+ break;
+ case 1:
+ falcon_interrupts ( efab, 1, 0 );
+ falcon_eventq_read_ack ( efab, ev_queue );
+ break;
+ case 2:
+ falcon_interrupts ( efab, 1, 1 );
+ break;
+ }
+}
+
+/*******************************************************************************
*
- * Etherboot interface
*
- **************************************************************************
- */
+ * Software open/close
+ *
+ *
+ *******************************************************************************/
-/**************************************************************************
-POLL - Wait for a frame
-***************************************************************************/
-static int etherfabric_poll ( struct nic *nic, int retrieve ) {
- struct efab_nic *efab = nic->priv_data;
- struct efab_event event;
- static struct efab_rx_buf *rx_buf = NULL;
- int i, drop = 0;
-
- /* Process the event queue until we hit either a packet
- * received event or an empty event slot.
- */
- while ( ( rx_buf == NULL ) &&
- efab->op->fetch_event ( efab, &event ) ) {
- drop = event.drop;
- if ( event.type == EFAB_EV_TX ) {
- /* TX completed - mark as done */
- DBG ( "TX id %x complete\n",
- efab->tx_buf.id );
- } else if ( event.type == EFAB_EV_RX ) {
- /* RX - find corresponding buffer */
- for ( i = 0 ; i < EFAB_RX_BUFS ; i++ ) {
- if ( efab->rx_bufs[i].id == event.rx_id ) {
- rx_buf = &efab->rx_bufs[i];
- rx_buf->len = event.rx_len;
- DBG ( "RX id %x (len %x) received\n",
- rx_buf->id, rx_buf->len );
- break;
- }
- }
- if ( ! rx_buf ) {
- EFAB_ERR ( "Invalid RX ID %x\n", event.rx_id );
- }
- } else if ( event.type == EFAB_EV_NONE ) {
- DBG ( "Ignorable event\n" );
- } else {
- DBG ( "Unknown event\n" );
- }
- }
+static void
+efab_free_resources ( struct efab_nic *efab )
+{
+ struct efab_ev_queue *ev_queue = &efab->ev_queue;
+ struct efab_rx_queue *rx_queue = &efab->rx_queue;
+ struct efab_tx_queue *tx_queue = &efab->tx_queue;
+ int i;
- /* If there is no packet, return 0 */
- if ( ! rx_buf )
- return 0;
+ for ( i = 0; i < EFAB_NUM_RX_DESC; i++ ) {
+ if ( rx_queue->buf[i] )
+ free_iob ( rx_queue->buf[i] );
+ }
- /* drop this event if necessary */
- if ( drop ) {
- DBG( "discarding RX event\n" );
- return 0;
+ for ( i = 0; i < EFAB_TXD_SIZE; i++ ) {
+ if ( tx_queue->buf[i] )
+ netdev_tx_complete ( efab->netdev, tx_queue->buf[i] );
}
- /* If we don't want to retrieve it just yet, return 1 */
- if ( ! retrieve )
- return 1;
+ if ( rx_queue->ring )
+ falcon_free_special_buffer ( rx_queue->ring );
- /* There seems to be a hardware race. The event can show up
- * on the event FIFO before the DMA has completed, so we
- * insert a tiny delay. If this proves unreliable, we should
- * switch to using event DMA rather than the event FIFO, since
- * event DMA ordering is guaranteed.
- */
- udelay ( 2 );
+ if ( tx_queue->ring )
+ falcon_free_special_buffer ( tx_queue->ring );
- /* Copy packet contents */
- nic->packetlen = rx_buf->len;
- memcpy ( nic->packet, rx_buf->addr, nic->packetlen );
+ if ( ev_queue->ring )
+ falcon_free_special_buffer ( ev_queue->ring );
- /* Give this buffer back to the NIC */
- efab_push_rx_buffer ( efab, rx_buf );
+ memset ( rx_queue, 0, sizeof ( *rx_queue ) );
+ memset ( tx_queue, 0, sizeof ( *tx_queue ) );
+ memset ( ev_queue, 0, sizeof ( *ev_queue ) );
- /* Prepare to receive next packet */
- rx_buf = NULL;
+ /* Ensure subsequent buffer allocations start at id 0 */
+ efab->buffer_head = 0;
+}
- return 1;
+static int
+efab_alloc_resources ( struct efab_nic *efab )
+{
+ struct efab_ev_queue *ev_queue = &efab->ev_queue;
+ struct efab_rx_queue *rx_queue = &efab->rx_queue;
+ struct efab_tx_queue *tx_queue = &efab->tx_queue;
+ size_t bytes;
+
+ /* Allocate the hardware event queue */
+ bytes = sizeof ( falcon_event_t ) * EFAB_TXD_SIZE;
+ ev_queue->ring = falcon_alloc_special_buffer ( efab, bytes,
+ &ev_queue->entry );
+ if ( !ev_queue->ring )
+ goto fail1;
+
+ /* Initialise the hardware event queue */
+ memset ( ev_queue->ring, 0xff, bytes );
+
+ /* Allocate the hardware tx queue */
+ bytes = sizeof ( falcon_tx_desc_t ) * EFAB_TXD_SIZE;
+ tx_queue->ring = falcon_alloc_special_buffer ( efab, bytes,
+ &tx_queue->entry );
+ if ( ! tx_queue->ring )
+ goto fail2;
+
+ /* Allocate the hardware rx queue */
+ bytes = sizeof ( falcon_rx_desc_t ) * EFAB_RXD_SIZE;
+ rx_queue->ring = falcon_alloc_special_buffer ( efab, bytes,
+ &rx_queue->entry );
+ if ( ! rx_queue->ring )
+ goto fail3;
+
+ return 0;
+
+fail3:
+ falcon_free_special_buffer ( tx_queue->ring );
+ tx_queue->ring = NULL;
+fail2:
+ falcon_free_special_buffer ( ev_queue->ring );
+ ev_queue->ring = NULL;
+fail1:
+ return -ENOMEM;
}
-/**************************************************************************
-TRANSMIT - Transmit a frame
-***************************************************************************/
-static void etherfabric_transmit ( struct nic *nic, const char *dest,
- unsigned int type, unsigned int size,
- const char *data ) {
- struct efab_nic *efab = nic->priv_data;
- unsigned int nstype = htons ( type );
-
- /* Fill TX buffer, pad to ETH_ZLEN */
- memcpy ( efab->tx_buf.addr, dest, ETH_ALEN );
- memcpy ( efab->tx_buf.addr + ETH_ALEN, nic->node_addr, ETH_ALEN );
- memcpy ( efab->tx_buf.addr + 2 * ETH_ALEN, &nstype, 2 );
- memcpy ( efab->tx_buf.addr + ETH_HLEN, data, size );
- size += ETH_HLEN;
- while ( size < ETH_ZLEN ) {
- efab->tx_buf.addr[size++] = '\0';
- }
- efab->tx_buf.len = size;
-
- /* Push TX descriptor */
- efab_push_tx_buffer ( efab, &efab->tx_buf );
-
- /* Allow enough time for the packet to be transmitted. This
- * is a temporary hack until we update to the new driver API.
- */
- udelay ( 20 );
+static int
+efab_init_mac ( struct efab_nic *efab )
+{
+ int count, rc;
+
+ /* This can take several seconds */
+ EFAB_LOG ( "Waiting for link..\n" );
+ for ( count=0; count<5; count++ ) {
+ rc = efab->mac_op->init ( efab );
+ if ( rc ) {
+ EFAB_ERR ( "Failed reinitialising MAC, error %s\n",
+ strerror ( rc ));
+ return rc;
+ }
- return;
+ /* Sleep for 2s to wait for the link to settle, either
+ * because we want to use it, or because we're about
+ * to reset the mac anyway
+ */
+ sleep ( 2 );
+
+ if ( ! efab->link_up ) {
+ EFAB_ERR ( "!\n" );
+ continue;
+ }
+
+ EFAB_LOG ( "\n%dMbps %s-duplex\n",
+ ( efab->link_options & LPA_10000 ? 10000 :
+ ( efab->link_options & LPA_1000 ? 1000 :
+ ( efab->link_options & LPA_100 ? 100 : 10 ) ) ),
+ ( efab->link_options & LPA_DUPLEX ?
+ "full" : "half" ) );
+
+ /* TODO: Move link state handling to the poll() routine */
+ netdev_link_up ( efab->netdev );
+ return 0;
+ }
+
+ EFAB_ERR ( "timed initialising MAC\n" );
+ return -ETIMEDOUT;
}
-/**************************************************************************
-DISABLE - Turn off ethernet interface
-***************************************************************************/
-static void etherfabric_disable ( struct nic *nic ) {
- struct efab_nic *efab = nic->priv_data;
+static void
+efab_close ( struct net_device *netdev )
+{
+ struct efab_nic *efab = netdev_priv ( netdev );
- efab->op->reset ( efab );
- if ( efab->membase )
- iounmap ( efab->membase );
+ falcon_fini_resources ( efab );
+ efab_free_resources ( efab );
+ efab->board_op->fini ( efab );
+ falcon_reset ( efab );
}
-/**************************************************************************
-IRQ - handle interrupts
-***************************************************************************/
-static void etherfabric_irq ( struct nic *nic, irq_action_t action ) {
- struct efab_nic *efab = nic->priv_data;
-
- switch ( action ) {
- case DISABLE :
- efab->op->mask_irq ( efab, 1 );
- break;
- case ENABLE :
- efab->op->mask_irq ( efab, 0 );
- break;
- case FORCE :
- /* Force NIC to generate a receive interrupt */
- efab->op->generate_irq ( efab );
- break;
- }
+static int
+efab_open ( struct net_device *netdev )
+{
+ struct efab_nic *efab = netdev_priv ( netdev );
+ struct efab_rx_queue *rx_queue = &efab->rx_queue;
+ int rc;
+
+ rc = falcon_reset ( efab );
+ if ( rc )
+ goto fail1;
+
+ rc = efab->board_op->init ( efab );
+ if ( rc )
+ goto fail2;
- return;
+ rc = falcon_init_sram ( efab );
+ if ( rc )
+ goto fail3;
+
+ /* Configure descriptor caches before pushing hardware queues */
+ falcon_setup_nic ( efab );
+
+ rc = efab_alloc_resources ( efab );
+ if ( rc )
+ goto fail4;
+
+ falcon_init_resources ( efab );
+
+ /* Push rx buffers */
+ rc = efab_fill_rx_queue ( efab, rx_queue );
+ if ( rc )
+ goto fail5;
+
+ /* Try and bring the interface up */
+ rc = efab_init_mac ( efab );
+ if ( rc )
+ goto fail6;
+
+ return 0;
+
+fail6:
+fail5:
+ efab_free_resources ( efab );
+fail4:
+fail3:
+ efab->board_op->fini ( efab );
+fail2:
+ falcon_reset ( efab );
+fail1:
+ return rc;
}
-static struct nic_operations etherfabric_operations = {
- .connect = dummy_connect,
- .poll = etherfabric_poll,
- .transmit = etherfabric_transmit,
- .irq = etherfabric_irq,
+static struct net_device_operations efab_operations = {
+ .open = efab_open,
+ .close = efab_close,
+ .transmit = efab_transmit,
+ .poll = efab_poll,
+ .irq = efab_irq,
};
-/**************************************************************************
-PROBE - Look for an adapter, this routine's visible to the outside
-***************************************************************************/
-static int etherfabric_probe ( struct nic *nic, struct pci_device *pci ) {
- static struct efab_nic efab;
- static int nic_port = 1;
- struct efab_buffers *buffers;
- int i;
+static void
+efab_remove ( struct pci_device *pci )
+{
+ struct net_device *netdev = pci_get_drvdata ( pci );
+ struct efab_nic *efab = netdev_priv ( netdev );
- /* Set up our private data structure */
- nic->priv_data = &efab;
- memset ( &efab, 0, sizeof ( efab ) );
- memset ( &efab_buffers, 0, sizeof ( efab_buffers ) );
+ if ( efab->membase ) {
+ falcon_reset ( efab );
- /* Hook in appropriate operations table. Do this early. */
- if ( pci->device == EF1002_DEVID ) {
- efab.op = &ef1002_operations;
- } else {
- efab.op = &falcon_operations;
+ iounmap ( efab->membase );
+ efab->membase = NULL;
}
- /* Initialise efab data structure */
- efab.pci = pci;
- buffers = ( ( struct efab_buffers * )
- ( ( ( void * ) &efab_buffers ) +
- ( - virt_to_bus ( &efab_buffers ) ) % EFAB_BUF_ALIGN ) );
- efab.eventq = buffers->eventq;
- efab.txd = buffers->txd;
- efab.rxd = buffers->rxd;
- efab.tx_buf.addr = buffers->tx_buf;
- for ( i = 0 ; i < EFAB_RX_BUFS ; i++ ) {
- efab.rx_bufs[i].addr = buffers->rx_buf[i];
+ if ( efab->nvo.nvs ) {
+ unregister_nvo ( &efab->nvo );
+ efab->nvo.nvs = NULL;
}
- /* Enable the PCI device */
- adjust_pci_device ( pci );
- nic->ioaddr = pci->ioaddr & ~3;
- nic->irqno = pci->irq;
+ unregister_netdev ( netdev );
+ netdev_nullify ( netdev );
+ netdev_put ( netdev );
+}
+
+static int
+efab_probe ( struct pci_device *pci,
+ const struct pci_device_id *id )
+{
+ struct net_device *netdev;
+ struct efab_nic *efab;
+ int rc, mmio_start, mmio_len;
+
+ /* Create the network adapter */
+ netdev = alloc_etherdev ( sizeof ( struct efab_nic ) );
+ if ( ! netdev ) {
+ rc = -ENOMEM;
+ goto fail1;
+ }
+
+ /* Initialise the network adapter, and initialise private storage */
+ netdev_init ( netdev, &efab_operations );
+ pci_set_drvdata ( pci, netdev );
+ netdev->dev = &pci->dev;
+
+ efab = netdev_priv ( netdev );
+ memset ( efab, 0, sizeof ( *efab ) );
+ efab->netdev = netdev;
/* Get iobase/membase */
- efab.iobase = nic->ioaddr;
- efab.op->get_membase ( &efab );
+ mmio_start = pci_bar_start ( pci, PCI_BASE_ADDRESS_2 );
+ mmio_len = pci_bar_size ( pci, PCI_BASE_ADDRESS_2 );
+ efab->membase = ioremap ( mmio_start, mmio_len );
+ EFAB_TRACE ( "BAR of %x bytes at phys %x mapped at %p\n",
+ mmio_len, mmio_start, efab->membase );
- /* Switch NIC ports (i.e. try different ports on each probe) */
- nic_port = 1 - nic_port;
- efab.port = nic_port;
+ /* Enable the PCI device */
+ adjust_pci_device ( pci );
+ efab->iobase = pci->ioaddr & ~3;
+
+ /* Determine the NIC variant */
+ falcon_probe_nic_variant ( efab, pci );
+
+ /* Read the SPI interface and determine the MAC address,
+ * and the board and phy variant. Hook in the op tables */
+ rc = falcon_probe_spi ( efab );
+ if ( rc )
+ goto fail2;
+ rc = falcon_probe_nvram ( efab );
+ if ( rc )
+ goto fail3;
+
+ memcpy ( netdev->ll_addr, efab->mac_addr, ETH_ALEN );
+
+ netdev_link_up ( netdev );
+ rc = register_netdev ( netdev );
+ if ( rc )
+ goto fail4;
+
+ /* Advertise non-volatile storage */
+ if ( efab->nvo.nvs ) {
+ rc = register_nvo ( &efab->nvo, netdev_settings ( netdev ) );
+ if ( rc )
+ goto fail5;
+ }
- /* Initialise hardware */
- if ( ! efab_init_nic ( &efab ) )
- return 0;
- memcpy ( nic->node_addr, efab.mac_addr, ETH_ALEN );
+ EFAB_LOG ( "Found %s EtherFabric %s %s revision %d\n", id->name,
+ efab->is_asic ? "ASIC" : "FPGA",
+ efab->phy_10g ? "10G" : "1G",
+ efab->pci_revision );
- /* point to NIC specific routines */
- nic->nic_op = &etherfabric_operations;
+ return 0;
- return 1;
+fail5:
+ unregister_netdev ( netdev );
+fail4:
+fail3:
+fail2:
+ iounmap ( efab->membase );
+ efab->membase = NULL;
+ netdev_put ( netdev );
+fail1:
+ return rc;
}
-static struct pci_device_id etherfabric_nics[] = {
-PCI_ROM(0x1924, 0xC101, "ef1002", "EtherFabric EF1002"),
-PCI_ROM(0x1924, 0x0703, "falcon", "EtherFabric Falcon"),
-};
-PCI_DRIVER ( etherfabric_driver, etherfabric_nics, PCI_NO_CLASS );
+static struct pci_device_id efab_nics[] = {
+ PCI_ROM(0x1924, 0x0703, "falcon", "EtherFabric Falcon"),
+ PCI_ROM(0x1924, 0x0710, "falconb0", "EtherFabric FalconB0"),
+};
-DRIVER ( "EFAB", nic_driver, pci_driver, etherfabric_driver,
- etherfabric_probe, etherfabric_disable );
+struct pci_driver etherfabric_driver __pci_driver = {
+ .ids = efab_nics,
+ .id_count = sizeof ( efab_nics ) / sizeof ( efab_nics[0] ),
+ .probe = efab_probe,
+ .remove = efab_remove,
+};
/*
* Local variables:
diff --git a/gpxe/src/drivers/net/etherfabric_nic.h b/gpxe/src/drivers/net/etherfabric_nic.h
new file mode 100644
index 00000000..4be50fbb
--- /dev/null
+++ b/gpxe/src/drivers/net/etherfabric_nic.h
@@ -0,0 +1,201 @@
+/**************************************************************************
+ *
+ * Etherboot driver for Level 5 Etherfabric network cards
+ *
+ * Written by Michael Brown <mbrown@fensystems.co.uk>
+ *
+ * Copyright Fen Systems Ltd. 2005
+ * Copyright Level 5 Networks Inc. 2005
+ *
+ * This software may be used and distributed according to the terms of
+ * the GNU General Public License (GPL), incorporated herein by
+ * reference. Drivers based on or derived from this code fall under
+ * the GPL and must retain the authorship, copyright and license
+ * notice.
+ *
+ **************************************************************************
+ */
+#ifndef EFAB_NIC_H
+#define EFAB_NIC_H
+#include <gpxe/bitbash.h>
+#include <gpxe/i2c.h>
+#include <gpxe/spi.h>
+#include <gpxe/nvo.h>
+#include <gpxe/if_ether.h>
+/**************************************************************************
+ *
+ * Constants and macros
+ *
+ **************************************************************************
+ */
+/* Board IDs. Early boards have no board_type, (e.g. EF1002 and 401/403)
+ * But newer boards are getting bigger...
+ */
+typedef enum {
+ EFAB_BOARD_INVALID = 0, /* Early boards do not have board rev. info. */
+ EFAB_BOARD_SFE4001 = 1,
+ EFAB_BOARD_SFE4002 = 2,
+ EFAB_BOARD_SFE4003 = 3,
+ /* Insert new types before here */
+ EFAB_BOARD_MAX
+} efab_board_type;
+
+/* PHY types. */
+typedef enum {
+ PHY_TYPE_AUTO = 0, /* on development board detect between CX4 & alaska */
+ PHY_TYPE_CX4_RTMR = 1,
+ PHY_TYPE_1GIG_ALASKA = 2,
+ PHY_TYPE_10XPRESS = 3,
+ PHY_TYPE_XFP = 4,
+ PHY_TYPE_CX4 = 5,
+ PHY_TYPE_PM8358 = 6,
+} phy_type_t;
+
+/**************************************************************************
+ *
+ * Hardware data structures and sizing
+ *
+ **************************************************************************
+ */
+
+#define dma_addr_t unsigned long
+typedef efab_qword_t falcon_rx_desc_t;
+typedef efab_qword_t falcon_tx_desc_t;
+typedef efab_qword_t falcon_event_t;
+
+#define EFAB_BUF_ALIGN 4096
+#define EFAB_RXD_SIZE 512
+#define EFAB_TXD_SIZE 512
+#define EFAB_EVQ_SIZE 512
+
+#define EFAB_NUM_RX_DESC 16
+#define EFAB_RX_BUF_SIZE 1600
+
+/**************************************************************************
+ *
+ * Data structures
+ *
+ **************************************************************************
+ */
+
+struct efab_nic;
+
+/* A buffer table allocation backing a tx dma, rx dma or eventq */
+struct efab_special_buffer {
+ dma_addr_t dma_addr;
+ int id;
+};
+
+/* A TX queue */
+struct efab_tx_queue {
+ /* The hardware ring */
+ falcon_tx_desc_t *ring;
+
+ /* The software ring storing io_buffers. */
+ struct io_buffer *buf[EFAB_TXD_SIZE];
+
+ /* The buffer table reservation pushed to hardware */
+ struct efab_special_buffer entry;
+
+ /* Software descriptor write ptr */
+ unsigned int write_ptr;
+
+ /* Hardware descriptor read ptr */
+ unsigned int read_ptr;
+};
+
+/* An RX queue */
+struct efab_rx_queue {
+ /* The hardware ring */
+ falcon_rx_desc_t *ring;
+
+ /* The software ring storing io_buffers */
+ struct io_buffer *buf[EFAB_NUM_RX_DESC];
+
+ /* The buffer table reservation pushed to hardware */
+ struct efab_special_buffer entry;
+
+ /* Descriptor write ptr, into both the hardware and software rings */
+ unsigned int write_ptr;
+
+ /* Hardware completion ptr */
+ unsigned int read_ptr;
+};
+
+/* An event queue */
+struct efab_ev_queue {
+ /* The hardware ring to push to hardware.
+ * Must be the first entry in the structure */
+ falcon_event_t *ring;
+
+ /* The buffer table reservation pushed to hardware */
+ struct efab_special_buffer entry;
+
+ /* Pointers into the ring */
+ unsigned int read_ptr;
+};
+
+struct efab_mac_operations {
+ int ( * init ) ( struct efab_nic *efab );
+};
+
+struct efab_phy_operations {
+ int ( * init ) ( struct efab_nic *efab );
+ unsigned int mmds;
+};
+
+struct efab_board_operations {
+ int ( * init ) ( struct efab_nic *efab );
+ void ( * fini ) ( struct efab_nic *efab );
+};
+
+struct efab_nic {
+ struct net_device *netdev;
+ int pci_revision;
+ int is_asic;
+
+ /* I2C bit-bashed interface */
+ struct i2c_bit_basher i2c_bb;
+
+ /** SPI bus and devices, and the user visible NVO area */
+ struct spi_bus spi_bus;
+ struct spi_device spi_flash;
+ struct spi_device spi_eeprom;
+ struct spi_device *spi;
+ struct nvo_block nvo;
+
+ /** Board, MAC, and PHY operations tables */
+ struct efab_board_operations *board_op;
+ struct efab_mac_operations *mac_op;
+ struct efab_phy_operations *phy_op;
+
+ /* PHY and board types */
+ int phy_addr;
+ int phy_type;
+ int phy_10g;
+ int board_type;
+
+ /** Memory and IO base */
+ void *membase;
+ unsigned int iobase;
+
+ /* Buffer table allocation head */
+ int buffer_head;
+
+ /* Queues */
+ struct efab_rx_queue rx_queue;
+ struct efab_tx_queue tx_queue;
+ struct efab_ev_queue ev_queue;
+
+ /** MAC address */
+ uint8_t mac_addr[ETH_ALEN];
+ /** GMII link options */
+ unsigned int link_options;
+ /** Link status */
+ int link_up;
+
+ /** INT_REG_KER */
+ efab_oword_t int_ker __attribute__ (( aligned ( 16 ) ));
+};
+#endif /* EFAB_NIC_H */
+
diff --git a/gpxe/src/drivers/net/forcedeth.c b/gpxe/src/drivers/net/forcedeth.c
index 54fadbd7..a30f1378 100644
--- a/gpxe/src/drivers/net/forcedeth.c
+++ b/gpxe/src/drivers/net/forcedeth.c
@@ -452,7 +452,7 @@ static int reg_delay(int offset, u32 mask,
delaymax -= delay;
if (delaymax < 0) {
if (msg)
- printf(msg);
+ printf("%s", msg);
return 1;
}
} while ((readl(base + offset) & mask) != target);
diff --git a/gpxe/src/drivers/net/ipoib.c b/gpxe/src/drivers/net/ipoib.c
index 16b2a0c8..f0d52044 100644
--- a/gpxe/src/drivers/net/ipoib.c
+++ b/gpxe/src/drivers/net/ipoib.c
@@ -33,9 +33,6 @@
* IP over Infiniband
*/
-/** IPoIB MTU */
-#define IPOIB_MTU 2048
-
/** Number of IPoIB data send work queue entries */
#define IPOIB_DATA_NUM_SEND_WQES 2
@@ -60,8 +57,6 @@ struct ipoib_queue_set {
struct ib_completion_queue *cq;
/** Queue pair */
struct ib_queue_pair *qp;
- /** Receive work queue fill level */
- unsigned int recv_fill;
/** Receive work queue maximum fill level */
unsigned int recv_max_fill;
};
@@ -90,49 +85,146 @@ struct ipoib_device {
int broadcast_attached;
};
+/** TID half used to identify get path record replies */
+#define IPOIB_TID_GET_PATH_REC 0x11111111UL
+
+/** TID half used to identify multicast member record replies */
+#define IPOIB_TID_MC_MEMBER_REC 0x22222222UL
+
+/** IPoIB metadata TID */
+static uint32_t ipoib_meta_tid = 0;
+
+/** Broadcast QPN used in IPoIB MAC addresses
+ *
+ * This is a guaranteed invalid real QPN
+ */
+#define IPOIB_BROADCAST_QPN 0xffffffffUL
+
+/** Broadcast IPoIB address */
+static struct ipoib_mac ipoib_broadcast = {
+ .qpn = ntohl ( IPOIB_BROADCAST_QPN ),
+ .gid.u.bytes = { 0xff, 0x12, 0x40, 0x1b, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff },
+};
+
+/****************************************************************************
+ *
+ * IPoIB peer cache
+ *
+ ****************************************************************************
+ */
+
/**
- * IPoIB path cache entry
+ * IPoIB peer address
*
* This serves a similar role to the ARP cache for Ethernet. (ARP
* *is* used on IPoIB; we have two caches to maintain.)
*/
-struct ipoib_cached_path {
- /** Destination GID */
- struct ib_gid gid;
- /** Destination LID */
- unsigned int dlid;
+struct ipoib_peer {
+ /** Key */
+ uint8_t key;
+ /** MAC address */
+ struct ipoib_mac mac;
+ /** LID */
+ unsigned int lid;
/** Service level */
unsigned int sl;
/** Rate */
unsigned int rate;
};
-/** Number of IPoIB path cache entries */
-#define IPOIB_NUM_CACHED_PATHS 2
+/** Number of IPoIB peer cache entries
+ *
+ * Must be a power of two.
+ */
+#define IPOIB_NUM_CACHED_PEERS 4
-/** IPoIB path cache */
-static struct ipoib_cached_path ipoib_path_cache[IPOIB_NUM_CACHED_PATHS];
+/** IPoIB peer address cache */
+static struct ipoib_peer ipoib_peer_cache[IPOIB_NUM_CACHED_PEERS];
-/** Oldest IPoIB path cache entry index */
-static unsigned int ipoib_path_cache_idx = 0;
+/** Oldest IPoIB peer cache entry index */
+static unsigned int ipoib_peer_cache_idx = 1;
-/** TID half used to identify get path record replies */
-#define IPOIB_TID_GET_PATH_REC 0x11111111UL
+/**
+ * Look up cached peer by key
+ *
+ * @v key Peer cache key
+ * @ret peer Peer cache entry, or NULL
+ */
+static struct ipoib_peer * ipoib_lookup_peer_by_key ( unsigned int key ) {
+ struct ipoib_peer *peer;
+ unsigned int i;
-/** TID half used to identify multicast member record replies */
-#define IPOIB_TID_MC_MEMBER_REC 0x22222222UL
+ for ( i = 0 ; i < IPOIB_NUM_CACHED_PEERS ; i++ ) {
+ peer = &ipoib_peer_cache[i];
+ if ( peer->key == key )
+ return peer;
+ }
-/** IPoIB metadata TID */
-static uint32_t ipoib_meta_tid = 0;
+ if ( key != 0 ) {
+ DBG ( "IPoIB warning: peer cache lost track of key %x while "
+ "still in use\n", key );
+ }
+ return NULL;
+}
-/** IPv4 broadcast GID */
-static const struct ib_gid ipv4_broadcast_gid = {
- { { 0xff, 0x12, 0x40, 0x1b, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff } }
-};
+/**
+ * Look up cached peer by GID
+ *
+ * @v gid Peer GID
+ * @ret peer Peer cache entry, or NULL
+ */
+static struct ipoib_peer *
+ipoib_lookup_peer_by_gid ( const struct ib_gid *gid ) {
+ struct ipoib_peer *peer;
+ unsigned int i;
-/** Maximum time we will wait for the broadcast join to succeed */
-#define IPOIB_JOIN_MAX_DELAY_MS 1000
+ for ( i = 0 ; i < IPOIB_NUM_CACHED_PEERS ; i++ ) {
+ peer = &ipoib_peer_cache[i];
+ if ( memcmp ( &peer->mac.gid, gid,
+ sizeof ( peer->mac.gid) ) == 0 ) {
+ return peer;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * Store GID and QPN in peer cache
+ *
+ * @v gid Peer GID
+ * @v qpn Peer QPN
+ * @ret peer Peer cache entry
+ */
+static struct ipoib_peer *
+ipoib_cache_peer ( const struct ib_gid *gid, unsigned long qpn ) {
+ struct ipoib_peer *peer;
+ unsigned int key;
+
+ /* Look for existing cache entry */
+ peer = ipoib_lookup_peer_by_gid ( gid );
+ if ( peer ) {
+ assert ( peer->mac.qpn = ntohl ( qpn ) );
+ return peer;
+ }
+
+ /* No entry found: create a new one */
+ key = ipoib_peer_cache_idx++;
+ peer = &ipoib_peer_cache[ key % IPOIB_NUM_CACHED_PEERS ];
+ if ( peer->key )
+ DBG ( "IPoIB peer %x evicted from cache\n", peer->key );
+
+ memset ( peer, 0, sizeof ( *peer ) );
+ peer->key = key;
+ peer->mac.qpn = htonl ( qpn );
+ memcpy ( &peer->mac.gid, gid, sizeof ( peer->mac.gid ) );
+ DBG ( "IPoIB peer %x has GID %08lx:%08lx:%08lx:%08lx and QPN %lx\n",
+ peer->key, htonl ( gid->u.dwords[0] ),
+ htonl ( gid->u.dwords[1] ), htonl ( gid->u.dwords[2] ),
+ htonl ( gid->u.dwords[3] ), qpn );
+ return peer;
+}
/****************************************************************************
*
@@ -141,37 +233,32 @@ static const struct ib_gid ipv4_broadcast_gid = {
****************************************************************************
*/
-/** Broadcast QPN used in IPoIB MAC addresses
- *
- * This is a guaranteed invalid real QPN
- */
-#define IPOIB_BROADCAST_QPN 0xffffffffUL
-
-/** Broadcast IPoIB address */
-static struct ipoib_mac ipoib_broadcast = {
- .qpn = ntohl ( IPOIB_BROADCAST_QPN ),
-};
-
/**
* Add IPoIB link-layer header
*
* @v iobuf I/O buffer
- * @v netdev Network device
- * @v net_protocol Network-layer protocol
* @v ll_dest Link-layer destination address
+ * @v ll_source Source link-layer address
+ * @v net_proto Network-layer protocol, in network-byte order
+ * @ret rc Return status code
*/
-static int ipoib_push ( struct io_buffer *iobuf,
- struct net_device *netdev __unused,
- struct net_protocol *net_protocol,
- const void *ll_dest ) {
+static int ipoib_push ( struct io_buffer *iobuf, const void *ll_dest,
+ const void *ll_source __unused, uint16_t net_proto ) {
struct ipoib_hdr *ipoib_hdr =
iob_push ( iobuf, sizeof ( *ipoib_hdr ) );
+ const struct ipoib_mac *dest_mac = ll_dest;
+ const struct ipoib_mac *src_mac = ll_source;
+ struct ipoib_peer *dest;
+ struct ipoib_peer *src;
+
+ /* Add link-layer addresses to cache */
+ dest = ipoib_cache_peer ( &dest_mac->gid, ntohl ( dest_mac->qpn ) );
+ src = ipoib_cache_peer ( &src_mac->gid, ntohl ( src_mac->qpn ) );
/* Build IPoIB header */
- memcpy ( &ipoib_hdr->pseudo.peer, ll_dest,
- sizeof ( ipoib_hdr->pseudo.peer ) );
- ipoib_hdr->real.proto = net_protocol->net_proto;
- ipoib_hdr->real.reserved = 0;
+ ipoib_hdr->proto = net_proto;
+ ipoib_hdr->u.peer.dest = dest->key;
+ ipoib_hdr->u.peer.src = src->key;
return 0;
}
@@ -180,15 +267,16 @@ static int ipoib_push ( struct io_buffer *iobuf,
* Remove IPoIB link-layer header
*
* @v iobuf I/O buffer
- * @v netdev Network device
- * @v net_proto Network-layer protocol, in network-byte order
- * @v ll_source Source link-layer address
+ * @ret ll_dest Link-layer destination address
+ * @ret ll_source Source link-layer address
+ * @ret net_proto Network-layer protocol, in network-byte order
* @ret rc Return status code
*/
-static int ipoib_pull ( struct io_buffer *iobuf,
- struct net_device *netdev __unused,
- uint16_t *net_proto, const void **ll_source ) {
+static int ipoib_pull ( struct io_buffer *iobuf, const void **ll_dest,
+ const void **ll_source, uint16_t *net_proto ) {
struct ipoib_hdr *ipoib_hdr = iobuf->data;
+ struct ipoib_peer *dest;
+ struct ipoib_peer *source;
/* Sanity check */
if ( iob_len ( iobuf ) < sizeof ( *ipoib_hdr ) ) {
@@ -200,9 +288,17 @@ static int ipoib_pull ( struct io_buffer *iobuf,
/* Strip off IPoIB header */
iob_pull ( iobuf, sizeof ( *ipoib_hdr ) );
+ /* Identify source and destination addresses, and clear
+ * reserved word in IPoIB header
+ */
+ dest = ipoib_lookup_peer_by_key ( ipoib_hdr->u.peer.dest );
+ source = ipoib_lookup_peer_by_key ( ipoib_hdr->u.peer.src );
+ ipoib_hdr->u.reserved = 0;
+
/* Fill in required fields */
- *net_proto = ipoib_hdr->real.proto;
- *ll_source = &ipoib_hdr->pseudo.peer;
+ *ll_dest = ( dest ? &dest->mac : &ipoib_broadcast );
+ *ll_source = ( source ? &source->mac : &ipoib_broadcast );
+ *net_proto = ipoib_hdr->proto;
return 0;
}
@@ -225,6 +321,21 @@ const char * ipoib_ntoa ( const void *ll_addr ) {
return buf;
}
+/**
+ * Hash multicast address
+ *
+ * @v af Address family
+ * @v net_addr Network-layer address
+ * @v ll_addr Link-layer address to fill in
+ * @ret rc Return status code
+ */
+static int ipoib_mc_hash ( unsigned int af __unused,
+ const void *net_addr __unused,
+ void *ll_addr __unused ) {
+
+ return -ENOTSUP;
+}
+
/** IPoIB protocol */
struct ll_protocol ipoib_protocol __ll_protocol = {
.name = "IPoIB",
@@ -235,6 +346,7 @@ struct ll_protocol ipoib_protocol __ll_protocol = {
.push = ipoib_push,
.pull = ipoib_pull,
.ntoa = ipoib_ntoa,
+ .mc_hash = ipoib_mc_hash,
};
/****************************************************************************
@@ -266,11 +378,17 @@ static void ipoib_destroy_qset ( struct ipoib_device *ipoib,
*
* @v ipoib IPoIB device
* @v qset Queue set
+ * @v num_cqes Number of completion queue entries
+ * @v cq_op Completion queue operations
+ * @v num_send_wqes Number of send work queue entries
+ * @v num_recv_wqes Number of receive work queue entries
+ * @v qkey Queue key
* @ret rc Return status code
*/
static int ipoib_create_qset ( struct ipoib_device *ipoib,
struct ipoib_queue_set *qset,
unsigned int num_cqes,
+ struct ib_completion_queue_operations *cq_op,
unsigned int num_send_wqes,
unsigned int num_recv_wqes,
unsigned long qkey ) {
@@ -285,7 +403,7 @@ static int ipoib_create_qset ( struct ipoib_device *ipoib,
qset->recv_max_fill = num_recv_wqes;
/* Allocate completion queue */
- qset->cq = ib_create_cq ( ibdev, num_cqes );
+ qset->cq = ib_create_cq ( ibdev, num_cqes, cq_op );
if ( ! qset->cq ) {
DBGC ( ipoib, "IPoIB %p could not allocate completion queue\n",
ipoib );
@@ -312,28 +430,6 @@ static int ipoib_create_qset ( struct ipoib_device *ipoib,
}
/**
- * Find path cache entry by GID
- *
- * @v gid GID
- * @ret entry Path cache entry, or NULL
- */
-static struct ipoib_cached_path *
-ipoib_find_cached_path ( struct ib_gid *gid ) {
- struct ipoib_cached_path *path;
- unsigned int i;
-
- for ( i = 0 ; i < IPOIB_NUM_CACHED_PATHS ; i++ ) {
- path = &ipoib_path_cache[i];
- if ( memcmp ( &path->gid, gid, sizeof ( *gid ) ) == 0 )
- return path;
- }
- DBG ( "IPoIB %08lx:%08lx:%08lx:%08lx cache miss\n",
- htonl ( gid->u.dwords[0] ), htonl ( gid->u.dwords[1] ),
- htonl ( gid->u.dwords[2] ), htonl ( gid->u.dwords[3] ) );
- return NULL;
-}
-
-/**
* Transmit path record request
*
* @v ipoib IPoIB device
@@ -344,36 +440,38 @@ static int ipoib_get_path_record ( struct ipoib_device *ipoib,
struct ib_gid *gid ) {
struct ib_device *ibdev = ipoib->ibdev;
struct io_buffer *iobuf;
- struct ib_mad_path_record *path_record;
+ struct ib_mad_sa *sa;
struct ib_address_vector av;
int rc;
/* Allocate I/O buffer */
- iobuf = alloc_iob ( sizeof ( *path_record ) );
+ iobuf = alloc_iob ( sizeof ( *sa ) );
if ( ! iobuf )
return -ENOMEM;
- iob_put ( iobuf, sizeof ( *path_record ) );
- path_record = iobuf->data;
- memset ( path_record, 0, sizeof ( *path_record ) );
+ iob_put ( iobuf, sizeof ( *sa ) );
+ sa = iobuf->data;
+ memset ( sa, 0, sizeof ( *sa ) );
/* Construct path record request */
- path_record->mad_hdr.base_version = IB_MGMT_BASE_VERSION;
- path_record->mad_hdr.mgmt_class = IB_MGMT_CLASS_SUBN_ADM;
- path_record->mad_hdr.class_version = 2;
- path_record->mad_hdr.method = IB_MGMT_METHOD_GET;
- path_record->mad_hdr.attr_id = htons ( IB_SA_ATTR_PATH_REC );
- path_record->mad_hdr.tid[0] = IPOIB_TID_GET_PATH_REC;
- path_record->mad_hdr.tid[1] = ipoib_meta_tid++;
- path_record->sa_hdr.comp_mask[1] =
+ sa->mad_hdr.base_version = IB_MGMT_BASE_VERSION;
+ sa->mad_hdr.mgmt_class = IB_MGMT_CLASS_SUBN_ADM;
+ sa->mad_hdr.class_version = 2;
+ sa->mad_hdr.method = IB_MGMT_METHOD_GET;
+ sa->mad_hdr.attr_id = htons ( IB_SA_ATTR_PATH_REC );
+ sa->mad_hdr.tid[0] = IPOIB_TID_GET_PATH_REC;
+ sa->mad_hdr.tid[1] = ipoib_meta_tid++;
+ sa->sa_hdr.comp_mask[1] =
htonl ( IB_SA_PATH_REC_DGID | IB_SA_PATH_REC_SGID );
- memcpy ( &path_record->dgid, gid, sizeof ( path_record->dgid ) );
- memcpy ( &path_record->sgid, &ibdev->port_gid,
- sizeof ( path_record->sgid ) );
+ memcpy ( &sa->sa_data.path_record.dgid, gid,
+ sizeof ( sa->sa_data.path_record.dgid ) );
+ memcpy ( &sa->sa_data.path_record.sgid, &ibdev->gid,
+ sizeof ( sa->sa_data.path_record.sgid ) );
/* Construct address vector */
memset ( &av, 0, sizeof ( av ) );
- av.dlid = ibdev->sm_lid;
- av.dest_qp = IB_SA_QPN;
+ av.lid = ibdev->sm_lid;
+ av.sl = ibdev->sm_sl;
+ av.qpn = IB_SA_QPN;
av.qkey = IB_GLOBAL_QKEY;
/* Post send request */
@@ -400,40 +498,41 @@ static int ipoib_mc_member_record ( struct ipoib_device *ipoib,
struct ib_gid *gid, int join ) {
struct ib_device *ibdev = ipoib->ibdev;
struct io_buffer *iobuf;
- struct ib_mad_mc_member_record *mc_member_record;
+ struct ib_mad_sa *sa;
struct ib_address_vector av;
int rc;
/* Allocate I/O buffer */
- iobuf = alloc_iob ( sizeof ( *mc_member_record ) );
+ iobuf = alloc_iob ( sizeof ( *sa ) );
if ( ! iobuf )
return -ENOMEM;
- iob_put ( iobuf, sizeof ( *mc_member_record ) );
- mc_member_record = iobuf->data;
- memset ( mc_member_record, 0, sizeof ( *mc_member_record ) );
+ iob_put ( iobuf, sizeof ( *sa ) );
+ sa = iobuf->data;
+ memset ( sa, 0, sizeof ( *sa ) );
/* Construct path record request */
- mc_member_record->mad_hdr.base_version = IB_MGMT_BASE_VERSION;
- mc_member_record->mad_hdr.mgmt_class = IB_MGMT_CLASS_SUBN_ADM;
- mc_member_record->mad_hdr.class_version = 2;
- mc_member_record->mad_hdr.method =
+ sa->mad_hdr.base_version = IB_MGMT_BASE_VERSION;
+ sa->mad_hdr.mgmt_class = IB_MGMT_CLASS_SUBN_ADM;
+ sa->mad_hdr.class_version = 2;
+ sa->mad_hdr.method =
( join ? IB_MGMT_METHOD_SET : IB_MGMT_METHOD_DELETE );
- mc_member_record->mad_hdr.attr_id = htons ( IB_SA_ATTR_MC_MEMBER_REC );
- mc_member_record->mad_hdr.tid[0] = IPOIB_TID_MC_MEMBER_REC;
- mc_member_record->mad_hdr.tid[1] = ipoib_meta_tid++;
- mc_member_record->sa_hdr.comp_mask[1] =
+ sa->mad_hdr.attr_id = htons ( IB_SA_ATTR_MC_MEMBER_REC );
+ sa->mad_hdr.tid[0] = IPOIB_TID_MC_MEMBER_REC;
+ sa->mad_hdr.tid[1] = ipoib_meta_tid++;
+ sa->sa_hdr.comp_mask[1] =
htonl ( IB_SA_MCMEMBER_REC_MGID | IB_SA_MCMEMBER_REC_PORT_GID |
IB_SA_MCMEMBER_REC_JOIN_STATE );
- mc_member_record->scope__join_state = 1;
- memcpy ( &mc_member_record->mgid, gid,
- sizeof ( mc_member_record->mgid ) );
- memcpy ( &mc_member_record->port_gid, &ibdev->port_gid,
- sizeof ( mc_member_record->port_gid ) );
+ sa->sa_data.mc_member_record.scope__join_state = 1;
+ memcpy ( &sa->sa_data.mc_member_record.mgid, gid,
+ sizeof ( sa->sa_data.mc_member_record.mgid ) );
+ memcpy ( &sa->sa_data.mc_member_record.port_gid, &ibdev->gid,
+ sizeof ( sa->sa_data.mc_member_record.port_gid ) );
/* Construct address vector */
memset ( &av, 0, sizeof ( av ) );
- av.dlid = ibdev->sm_lid;
- av.dest_qp = IB_SA_QPN;
+ av.lid = ibdev->sm_lid;
+ av.sl = ibdev->sm_sl;
+ av.qpn = IB_SA_QPN;
av.qkey = IB_GLOBAL_QKEY;
/* Post send request */
@@ -459,49 +558,51 @@ static int ipoib_transmit ( struct net_device *netdev,
struct io_buffer *iobuf ) {
struct ipoib_device *ipoib = netdev->priv;
struct ib_device *ibdev = ipoib->ibdev;
- struct ipoib_pseudo_hdr *ipoib_pshdr = iobuf->data;
+ struct ipoib_hdr *ipoib_hdr;
+ struct ipoib_peer *dest;
struct ib_address_vector av;
struct ib_gid *gid;
- struct ipoib_cached_path *path;
- int rc;
/* Sanity check */
- if ( iob_len ( iobuf ) < sizeof ( *ipoib_pshdr ) ) {
+ if ( iob_len ( iobuf ) < sizeof ( *ipoib_hdr ) ) {
DBGC ( ipoib, "IPoIB %p buffer too short\n", ipoib );
return -EINVAL;
}
- iob_pull ( iobuf, ( sizeof ( *ipoib_pshdr ) ) );
+ ipoib_hdr = iobuf->data;
/* Attempting transmission while link is down will put the
* queue pair into an error state, so don't try it.
*/
- if ( ! ibdev->link_up )
+ if ( ! ib_link_ok ( ibdev ) )
return -ENETUNREACH;
+ /* Identify destination address */
+ dest = ipoib_lookup_peer_by_key ( ipoib_hdr->u.peer.dest );
+ if ( ! dest )
+ return -ENXIO;
+ ipoib_hdr->u.reserved = 0;
+
/* Construct address vector */
memset ( &av, 0, sizeof ( av ) );
- av.qkey = IB_GLOBAL_QKEY;
+ av.qkey = ipoib->data_qkey;
av.gid_present = 1;
- if ( ipoib_pshdr->peer.qpn == htonl ( IPOIB_BROADCAST_QPN ) ) {
- /* Broadcast address */
- av.dest_qp = IB_BROADCAST_QPN;
- av.dlid = ipoib->broadcast_lid;
+ if ( dest->mac.qpn == htonl ( IPOIB_BROADCAST_QPN ) ) {
+ /* Broadcast */
+ av.qpn = IB_BROADCAST_QPN;
+ av.lid = ipoib->broadcast_lid;
gid = &ipoib->broadcast_gid;
} else {
- /* Unicast - look in path cache */
- path = ipoib_find_cached_path ( &ipoib_pshdr->peer.gid );
- if ( ! path ) {
- /* No path entry - get path record */
- rc = ipoib_get_path_record ( ipoib,
- &ipoib_pshdr->peer.gid );
- netdev_tx_complete ( netdev, iobuf );
- return rc;
+ /* Unicast */
+ if ( ! dest->lid ) {
+ /* No LID yet - get path record to fetch LID */
+ ipoib_get_path_record ( ipoib, &dest->mac.gid );
+ return -ENOENT;
}
- av.dest_qp = ntohl ( ipoib_pshdr->peer.qpn );
- av.dlid = path->dlid;
- av.rate = path->rate;
- av.sl = path->sl;
- gid = &ipoib_pshdr->peer.gid;
+ av.qpn = ntohl ( dest->mac.qpn );
+ av.lid = dest->lid;
+ av.rate = dest->rate;
+ av.sl = dest->sl;
+ gid = &dest->mac.gid;
}
memcpy ( &av.gid, gid, sizeof ( av.gid ) );
@@ -513,17 +614,15 @@ static int ipoib_transmit ( struct net_device *netdev,
*
* @v ibdev Infiniband device
* @v qp Queue pair
- * @v completion Completion
* @v iobuf I/O buffer
+ * @v rc Completion status code
*/
static void ipoib_data_complete_send ( struct ib_device *ibdev __unused,
struct ib_queue_pair *qp,
- struct ib_completion *completion,
- struct io_buffer *iobuf ) {
+ struct io_buffer *iobuf, int rc ) {
struct net_device *netdev = ib_qp_get_ownerdata ( qp );
- netdev_tx_complete_err ( netdev, iobuf,
- ( completion->syndrome ? -EIO : 0 ) );
+ netdev_tx_complete_err ( netdev, iobuf, rc );
}
/**
@@ -531,67 +630,67 @@ static void ipoib_data_complete_send ( struct ib_device *ibdev __unused,
*
* @v ibdev Infiniband device
* @v qp Queue pair
- * @v completion Completion
+ * @v av Address vector, or NULL
* @v iobuf I/O buffer
+ * @v rc Completion status code
*/
static void ipoib_data_complete_recv ( struct ib_device *ibdev __unused,
struct ib_queue_pair *qp,
- struct ib_completion *completion,
- struct io_buffer *iobuf ) {
+ struct ib_address_vector *av,
+ struct io_buffer *iobuf, int rc ) {
struct net_device *netdev = ib_qp_get_ownerdata ( qp );
struct ipoib_device *ipoib = netdev->priv;
- struct ipoib_pseudo_hdr *ipoib_pshdr;
-
- if ( completion->syndrome ) {
- netdev_rx_err ( netdev, iobuf, -EIO );
- goto done;
- }
+ struct ipoib_hdr *ipoib_hdr;
+ struct ipoib_peer *src;
- iob_put ( iobuf, completion->len );
- if ( iob_len ( iobuf ) < sizeof ( struct ib_global_route_header ) ) {
- DBGC ( ipoib, "IPoIB %p received data packet too short to "
- "contain GRH\n", ipoib );
- DBGC_HD ( ipoib, iobuf->data, iob_len ( iobuf ) );
- netdev_rx_err ( netdev, iobuf, -EIO );
- goto done;
+ if ( rc != 0 ) {
+ netdev_rx_err ( netdev, iobuf, rc );
+ return;
}
- iob_pull ( iobuf, sizeof ( struct ib_global_route_header ) );
- if ( iob_len ( iobuf ) < sizeof ( struct ipoib_real_hdr ) ) {
+ /* Sanity check */
+ if ( iob_len ( iobuf ) < sizeof ( struct ipoib_hdr ) ) {
DBGC ( ipoib, "IPoIB %p received data packet too short to "
"contain IPoIB header\n", ipoib );
DBGC_HD ( ipoib, iobuf->data, iob_len ( iobuf ) );
netdev_rx_err ( netdev, iobuf, -EIO );
- goto done;
+ return;
}
+ ipoib_hdr = iobuf->data;
- ipoib_pshdr = iob_push ( iobuf, sizeof ( *ipoib_pshdr ) );
- /* FIXME: fill in a MAC address for the sake of AoE! */
+ /* Parse source address */
+ if ( av->gid_present ) {
+ src = ipoib_cache_peer ( &av->gid, av->qpn );
+ ipoib_hdr->u.peer.src = src->key;
+ }
+ /* Hand off to network layer */
netdev_rx ( netdev, iobuf );
-
- done:
- ipoib->data.recv_fill--;
}
+/** IPoIB data completion operations */
+static struct ib_completion_queue_operations ipoib_data_cq_op = {
+ .complete_send = ipoib_data_complete_send,
+ .complete_recv = ipoib_data_complete_recv,
+};
+
/**
* Handle IPoIB metadata send completion
*
* @v ibdev Infiniband device
* @v qp Queue pair
- * @v completion Completion
* @v iobuf I/O buffer
+ * @v rc Completion status code
*/
static void ipoib_meta_complete_send ( struct ib_device *ibdev __unused,
struct ib_queue_pair *qp,
- struct ib_completion *completion,
- struct io_buffer *iobuf ) {
+ struct io_buffer *iobuf, int rc ) {
struct net_device *netdev = ib_qp_get_ownerdata ( qp );
struct ipoib_device *ipoib = netdev->priv;
- if ( completion->syndrome ) {
- DBGC ( ipoib, "IPoIB %p metadata TX completion error %x\n",
- ipoib, completion->syndrome );
+ if ( rc != 0 ) {
+ DBGC ( ipoib, "IPoIB %p metadata TX completion error: %s\n",
+ ipoib, strerror ( rc ) );
}
free_iob ( iobuf );
}
@@ -602,26 +701,25 @@ static void ipoib_meta_complete_send ( struct ib_device *ibdev __unused,
* @v ipoib IPoIB device
* @v path_record Path record
*/
-static void ipoib_recv_path_record ( struct ipoib_device *ipoib __unused,
- struct ib_mad_path_record *path_record ) {
- struct ipoib_cached_path *path;
+static void ipoib_recv_path_record ( struct ipoib_device *ipoib,
+ struct ib_path_record *path_record ) {
+ struct ipoib_peer *peer;
+
+ /* Locate peer cache entry */
+ peer = ipoib_lookup_peer_by_gid ( &path_record->dgid );
+ if ( ! peer ) {
+ DBGC ( ipoib, "IPoIB %p received unsolicited path record\n",
+ ipoib );
+ return;
+ }
/* Update path cache entry */
- path = &ipoib_path_cache[ipoib_path_cache_idx];
- memcpy ( &path->gid, &path_record->dgid, sizeof ( path->gid ) );
- path->dlid = ntohs ( path_record->dlid );
- path->sl = ( path_record->reserved__sl & 0x0f );
- path->rate = ( path_record->rate_selector__rate & 0x3f );
-
- DBG ( "IPoIB %08lx:%08lx:%08lx:%08lx dlid %x sl %x rate %x\n",
- htonl ( path->gid.u.dwords[0] ), htonl ( path->gid.u.dwords[1] ),
- htonl ( path->gid.u.dwords[2] ), htonl ( path->gid.u.dwords[3] ),
- path->dlid, path->sl, path->rate );
-
- /* Update path cache index */
- ipoib_path_cache_idx++;
- if ( ipoib_path_cache_idx == IPOIB_NUM_CACHED_PATHS )
- ipoib_path_cache_idx = 0;
+ peer->lid = ntohs ( path_record->dlid );
+ peer->sl = ( path_record->reserved__sl & 0x0f );
+ peer->rate = ( path_record->rate_selector__rate & 0x3f );
+
+ DBG ( "IPoIB peer %x has dlid %x sl %x rate %x\n",
+ peer->key, peer->lid, peer->sl, peer->rate );
}
/**
@@ -631,7 +729,7 @@ static void ipoib_recv_path_record ( struct ipoib_device *ipoib __unused,
* @v mc_member_record Multicast membership record
*/
static void ipoib_recv_mc_member_record ( struct ipoib_device *ipoib,
- struct ib_mad_mc_member_record *mc_member_record ) {
+ struct ib_mc_member_record *mc_member_record ) {
int joined;
int rc;
@@ -657,64 +755,64 @@ static void ipoib_recv_mc_member_record ( struct ipoib_device *ipoib,
*
* @v ibdev Infiniband device
* @v qp Queue pair
- * @v completion Completion
+ * @v av Address vector, or NULL
* @v iobuf I/O buffer
+ * @v rc Completion status code
*/
-static void ipoib_meta_complete_recv ( struct ib_device *ibdev __unused,
- struct ib_queue_pair *qp,
- struct ib_completion *completion,
- struct io_buffer *iobuf ) {
+static void
+ipoib_meta_complete_recv ( struct ib_device *ibdev __unused,
+ struct ib_queue_pair *qp,
+ struct ib_address_vector *av __unused,
+ struct io_buffer *iobuf, int rc ) {
struct net_device *netdev = ib_qp_get_ownerdata ( qp );
struct ipoib_device *ipoib = netdev->priv;
- union ib_mad *mad;
+ struct ib_mad_sa *sa;
- if ( completion->syndrome ) {
- DBGC ( ipoib, "IPoIB %p metadata RX completion error %x\n",
- ipoib, completion->syndrome );
+ if ( rc != 0 ) {
+ DBGC ( ipoib, "IPoIB %p metadata RX completion error: %s\n",
+ ipoib, strerror ( rc ) );
goto done;
}
- iob_put ( iobuf, completion->len );
- if ( iob_len ( iobuf ) < sizeof ( struct ib_global_route_header ) ) {
- DBGC ( ipoib, "IPoIB %p received metadata packet too short "
- "to contain GRH\n", ipoib );
- DBGC_HD ( ipoib, iobuf->data, iob_len ( iobuf ) );
- goto done;
- }
- iob_pull ( iobuf, sizeof ( struct ib_global_route_header ) );
- if ( iob_len ( iobuf ) < sizeof ( *mad ) ) {
+ if ( iob_len ( iobuf ) < sizeof ( *sa ) ) {
DBGC ( ipoib, "IPoIB %p received metadata packet too short "
"to contain reply\n", ipoib );
DBGC_HD ( ipoib, iobuf->data, iob_len ( iobuf ) );
goto done;
}
- mad = iobuf->data;
+ sa = iobuf->data;
- if ( mad->mad_hdr.status != 0 ) {
+ if ( sa->mad_hdr.status != 0 ) {
DBGC ( ipoib, "IPoIB %p metadata RX err status %04x\n",
- ipoib, ntohs ( mad->mad_hdr.status ) );
+ ipoib, ntohs ( sa->mad_hdr.status ) );
goto done;
}
- switch ( mad->mad_hdr.tid[0] ) {
+ switch ( sa->mad_hdr.tid[0] ) {
case IPOIB_TID_GET_PATH_REC:
- ipoib_recv_path_record ( ipoib, &mad->path_record );
+ ipoib_recv_path_record ( ipoib, &sa->sa_data.path_record );
break;
case IPOIB_TID_MC_MEMBER_REC:
- ipoib_recv_mc_member_record ( ipoib, &mad->mc_member_record );
+ ipoib_recv_mc_member_record ( ipoib,
+ &sa->sa_data.mc_member_record );
break;
default:
DBGC ( ipoib, "IPoIB %p unwanted response:\n",
ipoib );
- DBGC_HD ( ipoib, mad, sizeof ( *mad ) );
+ DBGC_HD ( ipoib, sa, sizeof ( *sa ) );
break;
}
done:
- ipoib->meta.recv_fill--;
free_iob ( iobuf );
}
+/** IPoIB metadata completion operations */
+static struct ib_completion_queue_operations ipoib_meta_cq_op = {
+ .complete_send = ipoib_meta_complete_send,
+ .complete_recv = ipoib_meta_complete_recv,
+};
+
/**
* Refill IPoIB receive ring
*
@@ -726,15 +824,14 @@ static void ipoib_refill_recv ( struct ipoib_device *ipoib,
struct io_buffer *iobuf;
int rc;
- while ( qset->recv_fill < qset->recv_max_fill ) {
- iobuf = alloc_iob ( IPOIB_MTU );
+ while ( qset->qp->recv.fill < qset->recv_max_fill ) {
+ iobuf = alloc_iob ( IPOIB_PKT_LEN );
if ( ! iobuf )
break;
if ( ( rc = ib_post_recv ( ibdev, qset->qp, iobuf ) ) != 0 ) {
free_iob ( iobuf );
break;
}
- qset->recv_fill++;
}
}
@@ -747,10 +844,8 @@ static void ipoib_poll ( struct net_device *netdev ) {
struct ipoib_device *ipoib = netdev->priv;
struct ib_device *ibdev = ipoib->ibdev;
- ib_poll_cq ( ibdev, ipoib->meta.cq, ipoib_meta_complete_send,
- ipoib_meta_complete_recv );
- ib_poll_cq ( ibdev, ipoib->data.cq, ipoib_data_complete_send,
- ipoib_data_complete_recv );
+ ib_poll_cq ( ibdev, ipoib->meta.cq );
+ ib_poll_cq ( ibdev, ipoib->data.cq );
ipoib_refill_recv ( ipoib, &ipoib->meta );
ipoib_refill_recv ( ipoib, &ipoib->data );
}
@@ -834,6 +929,7 @@ static int ipoib_open ( struct net_device *netdev ) {
/* Allocate metadata queue set */
if ( ( rc = ipoib_create_qset ( ipoib, &ipoib->meta,
IPOIB_META_NUM_CQES,
+ &ipoib_meta_cq_op,
IPOIB_META_NUM_SEND_WQES,
IPOIB_META_NUM_RECV_WQES,
IB_GLOBAL_QKEY ) ) != 0 ) {
@@ -845,6 +941,7 @@ static int ipoib_open ( struct net_device *netdev ) {
/* Allocate data queue set */
if ( ( rc = ipoib_create_qset ( ipoib, &ipoib->data,
IPOIB_DATA_NUM_CQES,
+ &ipoib_data_cq_op,
IPOIB_DATA_NUM_SEND_WQES,
IPOIB_DATA_NUM_RECV_WQES,
IB_GLOBAL_QKEY ) ) != 0 ) {
@@ -923,15 +1020,15 @@ static void ipoib_set_ib_params ( struct ipoib_device *ipoib ) {
/* Calculate GID portion of MAC address based on port GID */
mac = ( ( struct ipoib_mac * ) netdev->ll_addr );
- memcpy ( &mac->gid, &ibdev->port_gid, sizeof ( mac->gid ) );
+ memcpy ( &mac->gid, &ibdev->gid, sizeof ( mac->gid ) );
/* Calculate broadcast GID based on partition key */
- memcpy ( &ipoib->broadcast_gid, &ipv4_broadcast_gid,
+ memcpy ( &ipoib->broadcast_gid, &ipoib_broadcast.gid,
sizeof ( ipoib->broadcast_gid ) );
ipoib->broadcast_gid.u.words[2] = htons ( ibdev->pkey );
/* Set net device link state to reflect Infiniband link state */
- if ( ibdev->link_up ) {
+ if ( ib_link_ok ( ibdev ) ) {
netdev_link_up ( netdev );
} else {
netdev_link_down ( netdev );
diff --git a/gpxe/src/drivers/net/natsemi.c b/gpxe/src/drivers/net/natsemi.c
index 028b905c..84bfd7ab 100644
--- a/gpxe/src/drivers/net/natsemi.c
+++ b/gpxe/src/drivers/net/natsemi.c
@@ -61,7 +61,8 @@
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
-#include <io.h>
+#include <string.h>
+#include <gpxe/io.h>
#include <errno.h>
#include <byteswap.h>
#include <unistd.h>
diff --git a/gpxe/src/drivers/net/ne2k_isa.c b/gpxe/src/drivers/net/ne2k_isa.c
new file mode 100644
index 00000000..f8a45cc8
--- /dev/null
+++ b/gpxe/src/drivers/net/ne2k_isa.c
@@ -0,0 +1,373 @@
+/**************************************************************************
+ ETHERBOOT - BOOTP/TFTP Bootstrap Program
+
+ Author: Martin Renters
+ Date: May/94
+
+ This code is based heavily on David Greenman's if_ed.c driver
+
+ Copyright (C) 1993-1994, David Greenman, Martin Renters.
+ This software may be used, modified, copied, distributed, and sold, in
+ both source and binary form provided that the above copyright and these
+ terms are retained. Under no circumstances are the authors responsible for
+ the proper functioning of this software, nor do the authors assume any
+ responsibility for damages incurred with its use.
+
+ Multicast support added by Timothy Legge (timlegge@users.sourceforge.net) 09/28/2003
+ Relocation support added by Ken Yap (ken_yap@users.sourceforge.net) 28/12/02
+ Card Detect support adapted from the eCos driver (Christian Plessl <cplessl@ee.ethz.ch>)
+ Extracted from ns8390.c and adapted by Pantelis Koukousoulas <pktoss@gmail.com>
+ **************************************************************************/
+
+#include "ns8390.h"
+#include "etherboot.h"
+#include "nic.h"
+#include <gpxe/ethernet.h>
+#include <gpxe/isa.h>
+#include <errno.h>
+
+#define ASIC_PIO NE_DATA
+
+static unsigned char eth_vendor, eth_flags;
+static unsigned short eth_nic_base, eth_asic_base;
+static unsigned char eth_memsize, eth_rx_start, eth_tx_start;
+static Address eth_bmem, eth_rmem;
+static unsigned char eth_drain_receiver;
+
+static struct nic_operations ne_operations;
+static void ne_reset(struct nic *nic, struct isa_device *isa);
+
+static isa_probe_addr_t ne_probe_addrs[] = { 0x300, 0x280, 0x320, 0x340, 0x380, 0x220, };
+
+/**************************************************************************
+ ETH_PIO_READ - Read a frame via Programmed I/O
+ **************************************************************************/
+static void eth_pio_read(unsigned int src, unsigned char *dst, unsigned int cnt) {
+ outb(D8390_COMMAND_RD2 | D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
+ outb(cnt, eth_nic_base + D8390_P0_RBCR0);
+ outb(cnt >> 8, eth_nic_base + D8390_P0_RBCR1);
+ outb(src, eth_nic_base + D8390_P0_RSAR0);
+ outb(src >> 8, eth_nic_base + D8390_P0_RSAR1);
+ outb(D8390_COMMAND_RD0 | D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
+ if (eth_flags & FLAG_16BIT)
+ cnt = (cnt + 1) >> 1;
+
+ while (cnt--) {
+ if (eth_flags & FLAG_16BIT) {
+ *((unsigned short *) dst) = inw(eth_asic_base + ASIC_PIO);
+ dst += 2;
+ } else
+ *(dst++) = inb(eth_asic_base + ASIC_PIO);
+ }
+}
+
+/**************************************************************************
+ ETH_PIO_WRITE - Write a frame via Programmed I/O
+ **************************************************************************/
+static void eth_pio_write(const unsigned char *src, unsigned int dst,
+ unsigned int cnt) {
+ outb(D8390_COMMAND_RD2 | D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
+ outb(D8390_ISR_RDC, eth_nic_base + D8390_P0_ISR);
+ outb(cnt, eth_nic_base + D8390_P0_RBCR0);
+ outb(cnt >> 8, eth_nic_base + D8390_P0_RBCR1);
+ outb(dst, eth_nic_base + D8390_P0_RSAR0);
+ outb(dst >> 8, eth_nic_base + D8390_P0_RSAR1);
+ outb(D8390_COMMAND_RD1 | D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
+ if (eth_flags & FLAG_16BIT)
+ cnt = (cnt + 1) >> 1;
+
+ while (cnt--) {
+
+ if (eth_flags & FLAG_16BIT) {
+ outw(*((unsigned short *) src), eth_asic_base + ASIC_PIO);
+ src += 2;
+ } else
+ outb(*(src++), eth_asic_base + ASIC_PIO);
+ }
+}
+
+/**************************************************************************
+ enable_multicast - Enable Multicast
+ **************************************************************************/
+static void enable_multicast(unsigned short eth_nic_base) {
+ unsigned char mcfilter[8];
+ int i;
+
+ memset(mcfilter, 0xFF, 8);
+ outb(4, eth_nic_base + D8390_P0_RCR);
+ outb(D8390_COMMAND_RD2 + D8390_COMMAND_PS1, eth_nic_base + D8390_P0_COMMAND);
+ for (i = 0; i < 8; i++) {
+ outb(mcfilter[i], eth_nic_base + 8 + i);
+ if (inb(eth_nic_base + 8 + i) != mcfilter[i])
+ DBG("Error SMC 83C690 Multicast filter read/write mishap %d\n",
+ i);
+ }
+ outb(D8390_COMMAND_RD2 + D8390_COMMAND_PS0, eth_nic_base + D8390_P0_COMMAND);
+ outb(4 | 0x08, eth_nic_base + D8390_P0_RCR);
+}
+
+/**************************************************************************
+ NE_PROBE1 - Look for an adapter on the ISA bus
+ **************************************************************************/
+static int ne_probe1(isa_probe_addr_t ioaddr) {
+ //From the eCos driver
+ unsigned int regd;
+ unsigned int state;
+
+ state = inb(ioaddr);
+ outb(ioaddr, D8390_COMMAND_RD2 | D8390_COMMAND_PS1 | D8390_COMMAND_STP);
+ regd = inb(ioaddr + D8390_P0_TCR);
+
+ if (inb(ioaddr + D8390_P0_TCR)) {
+ outb(ioaddr, state);
+ outb(ioaddr + 0x0d, regd);
+ return 0;
+ }
+
+ return 1;
+}
+
+/**************************************************************************
+ NE_PROBE - Initialize an adapter ???
+ **************************************************************************/
+static int ne_probe(struct nic *nic, struct isa_device *isa) {
+ int i;
+ unsigned char c;
+ unsigned char romdata[16];
+ unsigned char testbuf[32];
+
+ eth_vendor = VENDOR_NONE;
+ eth_drain_receiver = 0;
+
+ nic->irqno = 0;
+ nic->ioaddr = isa->ioaddr;
+ eth_nic_base = isa->ioaddr;
+
+ /******************************************************************
+ Search for NE1000/2000 if no WD/SMC or 3com cards
+ ******************************************************************/
+ if (eth_vendor == VENDOR_NONE) {
+
+ static unsigned char test[] = "NE*000 memory";
+
+ eth_bmem = 0; /* No shared memory */
+
+ eth_flags = FLAG_PIO;
+ eth_asic_base = eth_nic_base + NE_ASIC_OFFSET;
+ eth_memsize = MEM_16384;
+ eth_tx_start = 32;
+ eth_rx_start = 32 + D8390_TXBUF_SIZE;
+ c = inb(eth_asic_base + NE_RESET);
+ outb(c, eth_asic_base + NE_RESET);
+ (void) inb(0x84);
+ outb(D8390_COMMAND_STP | D8390_COMMAND_RD2, eth_nic_base
+ + D8390_P0_COMMAND);
+ outb(D8390_RCR_MON, eth_nic_base + D8390_P0_RCR);
+ outb(D8390_DCR_FT1 | D8390_DCR_LS, eth_nic_base + D8390_P0_DCR);
+ outb(MEM_8192, eth_nic_base + D8390_P0_PSTART);
+ outb(MEM_16384, eth_nic_base + D8390_P0_PSTOP);
+ eth_pio_write((unsigned char *) test, 8192, sizeof(test));
+ eth_pio_read(8192, testbuf, sizeof(test));
+ if (!memcmp(test, testbuf, sizeof(test)))
+ goto out;
+ eth_flags |= FLAG_16BIT;
+ eth_memsize = MEM_32768;
+ eth_tx_start = 64;
+ eth_rx_start = 64 + D8390_TXBUF_SIZE;
+ outb(D8390_DCR_WTS | D8390_DCR_FT1 | D8390_DCR_LS, eth_nic_base
+ + D8390_P0_DCR);
+ outb(MEM_16384, eth_nic_base + D8390_P0_PSTART);
+ outb(MEM_32768, eth_nic_base + D8390_P0_PSTOP);
+ eth_pio_write((unsigned char *) test, 16384, sizeof(test));
+ eth_pio_read(16384, testbuf, sizeof(test));
+ if (!memcmp(testbuf, test, sizeof(test)))
+ goto out;
+
+
+out:
+ if (eth_nic_base == 0)
+ return (0);
+ if (eth_nic_base > ISA_MAX_ADDR) /* PCI probably */
+ eth_flags |= FLAG_16BIT;
+ eth_vendor = VENDOR_NOVELL;
+ eth_pio_read(0, romdata, sizeof(romdata));
+ for (i = 0; i < ETH_ALEN; i++) {
+ nic->node_addr[i] = romdata[i + ((eth_flags & FLAG_16BIT) ? i : 0)];
+ }
+ nic->ioaddr = eth_nic_base;
+ DBG("\nNE%c000 base %4.4x, MAC Addr %s\n",
+ (eth_flags & FLAG_16BIT) ? '2' : '1', eth_nic_base, eth_ntoa(
+ nic->node_addr));
+ }
+
+ if (eth_vendor == VENDOR_NONE)
+ return (0);
+
+ if (eth_vendor != VENDOR_3COM)
+ eth_rmem = eth_bmem;
+
+ ne_reset(nic, isa);
+ nic->nic_op = &ne_operations;
+ return 1;
+}
+
+
+/**************************************************************************
+ NE_DISABLE - Turn off adapter
+ **************************************************************************/
+static void ne_disable(struct nic *nic, struct isa_device *isa) {
+ ne_reset(nic, isa);
+}
+
+
+/**************************************************************************
+ NE_RESET - Reset adapter
+ **************************************************************************/
+static void ne_reset(struct nic *nic, struct isa_device *isa __unused)
+{
+ int i;
+
+ eth_drain_receiver = 0;
+ outb(D8390_COMMAND_PS0 | D8390_COMMAND_RD2 |
+ D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND);
+ if (eth_flags & FLAG_16BIT)
+ outb(0x49, eth_nic_base+D8390_P0_DCR);
+ else
+ outb(0x48, eth_nic_base+D8390_P0_DCR);
+ outb(0, eth_nic_base+D8390_P0_RBCR0);
+ outb(0, eth_nic_base+D8390_P0_RBCR1);
+ outb(0x20, eth_nic_base+D8390_P0_RCR); /* monitor mode */
+ outb(2, eth_nic_base+D8390_P0_TCR);
+ outb(eth_tx_start, eth_nic_base+D8390_P0_TPSR);
+ outb(eth_rx_start, eth_nic_base+D8390_P0_PSTART);
+
+ outb(eth_memsize, eth_nic_base+D8390_P0_PSTOP);
+ outb(eth_memsize - 1, eth_nic_base+D8390_P0_BOUND);
+ outb(0xFF, eth_nic_base+D8390_P0_ISR);
+ outb(0, eth_nic_base+D8390_P0_IMR);
+ outb(D8390_COMMAND_PS1 |
+ D8390_COMMAND_RD2 | D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND);
+
+ for (i=0; i<ETH_ALEN; i++)
+ outb(nic->node_addr[i], eth_nic_base+D8390_P1_PAR0+i);
+ for (i=0; i<ETH_ALEN; i++)
+ outb(0xFF, eth_nic_base+D8390_P1_MAR0+i);
+ outb(eth_rx_start, eth_nic_base+D8390_P1_CURR);
+ outb(D8390_COMMAND_PS0 |
+ D8390_COMMAND_RD2 | D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
+ outb(0xFF, eth_nic_base+D8390_P0_ISR);
+ outb(0, eth_nic_base+D8390_P0_TCR); /* transmitter on */
+ outb(4, eth_nic_base+D8390_P0_RCR); /* allow rx broadcast frames */
+
+ enable_multicast(eth_nic_base);
+}
+
+
+/**************************************************************************
+ NE_POLL - Wait for a frame
+ **************************************************************************/
+static int ne_poll(struct nic *nic __unused, int retrieve __unused)
+{
+ int ret = 0;
+ unsigned char rstat, curr, next;
+ unsigned short len, frag;
+ unsigned short pktoff;
+ unsigned char *p;
+ struct ringbuffer pkthdr;
+
+ rstat = inb(eth_nic_base+D8390_P0_RSR);
+ if (!(rstat & D8390_RSTAT_PRX)) return(0);
+ next = inb(eth_nic_base+D8390_P0_BOUND)+1;
+ if (next >= eth_memsize) next = eth_rx_start;
+ outb(D8390_COMMAND_PS1, eth_nic_base+D8390_P0_COMMAND);
+ curr = inb(eth_nic_base+D8390_P1_CURR);
+ outb(D8390_COMMAND_PS0, eth_nic_base+D8390_P0_COMMAND);
+ if (curr >= eth_memsize) curr=eth_rx_start;
+ if (curr == next) return(0);
+
+ if ( ! retrieve ) return 1;
+
+ pktoff = next << 8;
+ if (eth_flags & FLAG_PIO)
+ eth_pio_read(pktoff, (unsigned char *)&pkthdr, 4);
+ else
+ memcpy(&pkthdr, bus_to_virt(eth_rmem + pktoff), 4);
+ pktoff += sizeof(pkthdr);
+ /* incoming length includes FCS so must sub 4 */
+ len = pkthdr.len - 4;
+ if ((pkthdr.status & D8390_RSTAT_PRX) == 0 || len < ETH_ZLEN
+ || len> ETH_FRAME_LEN) {
+ DBG("Bogus packet, ignoring\n");
+ return (0);
+ }
+ else {
+ p = nic->packet;
+ nic->packetlen = len; /* available to caller */
+ frag = (eth_memsize << 8) - pktoff;
+ if (len> frag) { /* We have a wrap-around */
+ /* read first part */
+ if (eth_flags & FLAG_PIO)
+ eth_pio_read(pktoff, p, frag);
+ else
+ memcpy(p, bus_to_virt(eth_rmem + pktoff), frag);
+ pktoff = eth_rx_start << 8;
+ p += frag;
+ len -= frag;
+ }
+ /* read second part */
+ if (eth_flags & FLAG_PIO)
+ eth_pio_read(pktoff, p, len);
+ else
+ memcpy(p, bus_to_virt(eth_rmem + pktoff), len);
+ ret = 1;
+ }
+ next = pkthdr.next; /* frame number of next packet */
+ if (next == eth_rx_start)
+ next = eth_memsize;
+ outb(next-1, eth_nic_base+D8390_P0_BOUND);
+ return(ret);
+}
+
+
+/**************************************************************************
+ NE_TRANSMIT - Transmit a frame
+ **************************************************************************/
+static void ne_transmit(struct nic *nic, const char *d, /* Destination */
+unsigned int t, /* Type */
+unsigned int s, /* size */
+const char *p) { /* Packet */
+
+ /* Programmed I/O */
+ unsigned short type;
+ type = (t >> 8) | (t << 8);
+ eth_pio_write((unsigned char *) d, eth_tx_start << 8, ETH_ALEN);
+ eth_pio_write(nic->node_addr, (eth_tx_start << 8) + ETH_ALEN, ETH_ALEN);
+ /* bcc generates worse code without (const+const) below */
+ eth_pio_write((unsigned char *) &type, (eth_tx_start << 8) + (ETH_ALEN
+ + ETH_ALEN), 2);
+ eth_pio_write((unsigned char *) p, (eth_tx_start << 8) + ETH_HLEN, s);
+ s += ETH_HLEN;
+ if (s < ETH_ZLEN)
+ s = ETH_ZLEN;
+
+ outb(D8390_COMMAND_PS0 | D8390_COMMAND_RD2 | D8390_COMMAND_STA,
+ eth_nic_base + D8390_P0_COMMAND);
+ outb(eth_tx_start, eth_nic_base + D8390_P0_TPSR);
+ outb(s, eth_nic_base + D8390_P0_TBCR0);
+ outb(s >> 8, eth_nic_base + D8390_P0_TBCR1);
+
+ outb(D8390_COMMAND_PS0 | D8390_COMMAND_TXP | D8390_COMMAND_RD2
+ | D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
+}
+
+static struct nic_operations ne_operations = { .connect = dummy_connect,
+ .poll = ne_poll, .transmit = ne_transmit, .irq = dummy_irq,
+};
+
+ISA_DRIVER ( ne_driver, ne_probe_addrs, ne_probe1,
+ GENERIC_ISAPNP_VENDOR, 0x0600 );
+
+DRIVER ( "ne", nic_driver, isapnp_driver, ne_driver,
+ ne_probe, ne_disable );
+
+ISA_ROM("ne","NE1000/2000 and clones");
diff --git a/gpxe/src/drivers/net/phantom/phantom.c b/gpxe/src/drivers/net/phantom/phantom.c
index 6c7d1fc9..33c76f62 100644
--- a/gpxe/src/drivers/net/phantom/phantom.c
+++ b/gpxe/src/drivers/net/phantom/phantom.c
@@ -25,12 +25,14 @@
#include <assert.h>
#include <byteswap.h>
#include <gpxe/pci.h>
+#include <gpxe/io.h>
#include <gpxe/malloc.h>
#include <gpxe/iobuf.h>
#include <gpxe/netdevice.h>
#include <gpxe/if_ether.h>
#include <gpxe/ethernet.h>
#include <gpxe/spi.h>
+#include <gpxe/settings.h>
#include "phantom.h"
/**
@@ -40,11 +42,8 @@
*
*/
-/** Maximum time to wait for SPI lock */
-#define PHN_SPI_LOCK_TIMEOUT_MS 100
-
-/** Maximum time to wait for SPI command to be issued */
-#define PHN_SPI_CMD_TIMEOUT_MS 100
+/** Maximum number of ports */
+#define PHN_MAX_NUM_PORTS 4
/** Maximum time to wait for command PEG to initialise
*
@@ -71,6 +70,9 @@
/** Maximum time to wait for test memory */
#define PHN_TEST_MEM_TIMEOUT_MS 100
+/** Maximum time to wait for CLP command to be issued */
+#define PHN_CLP_CMD_TIMEOUT_MS 500
+
/** Link state poll frequency
*
* The link state will be checked once in every N calls to poll().
@@ -105,10 +107,41 @@ struct phantom_descriptor_rings {
volatile uint32_t cmd_cons;
};
-/** A Phantom NIC port */
-struct phantom_nic_port {
- /** Phantom NIC containing this port */
- struct phantom_nic *phantom;
+/** RX context creation request and response buffers */
+struct phantom_create_rx_ctx_rqrsp {
+ struct {
+ struct nx_hostrq_rx_ctx_s rx_ctx;
+ struct nx_hostrq_rds_ring_s rds;
+ struct nx_hostrq_sds_ring_s sds;
+ } __unm_dma_aligned hostrq;
+ struct {
+ struct nx_cardrsp_rx_ctx_s rx_ctx;
+ struct nx_cardrsp_rds_ring_s rds;
+ struct nx_cardrsp_sds_ring_s sds;
+ } __unm_dma_aligned cardrsp;
+};
+
+/** TX context creation request and response buffers */
+struct phantom_create_tx_ctx_rqrsp {
+ struct {
+ struct nx_hostrq_tx_ctx_s tx_ctx;
+ } __unm_dma_aligned hostrq;
+ struct {
+ struct nx_cardrsp_tx_ctx_s tx_ctx;
+ } __unm_dma_aligned cardrsp;
+};
+
+/** A Phantom NIC */
+struct phantom_nic {
+ /** BAR 0 */
+ void *bar0;
+ /** Current CRB window */
+ unsigned long crb_window;
+ /** CRB window access method */
+ unsigned long ( *crb_access ) ( struct phantom_nic *phantom,
+ unsigned long reg );
+
+
/** Port number */
unsigned int port;
@@ -143,73 +176,18 @@ struct phantom_nic_port {
struct io_buffer *cds_iobuf[PHN_NUM_CDS];
- /** Link state poll timer */
- unsigned long link_poll_timer;
-
-
/** Descriptor rings */
struct phantom_descriptor_rings *desc;
-};
-
-/** RX context creation request and response buffers */
-struct phantom_create_rx_ctx_rqrsp {
- struct {
- struct nx_hostrq_rx_ctx_s rx_ctx;
- struct nx_hostrq_rds_ring_s rds;
- struct nx_hostrq_sds_ring_s sds;
- } __unm_dma_aligned hostrq;
- struct {
- struct nx_cardrsp_rx_ctx_s rx_ctx;
- struct nx_cardrsp_rds_ring_s rds;
- struct nx_cardrsp_sds_ring_s sds;
- } __unm_dma_aligned cardrsp;
-};
-
-/** TX context creation request and response buffers */
-struct phantom_create_tx_ctx_rqrsp {
- struct {
- struct nx_hostrq_tx_ctx_s tx_ctx;
- } __unm_dma_aligned hostrq;
- struct {
- struct nx_cardrsp_tx_ctx_s tx_ctx;
- } __unm_dma_aligned cardrsp;
-};
-
-/** A Phantom DMA buffer area */
-union phantom_dma_buffer {
- /** Dummy area required for (read-only) self-tests */
- uint8_t dummy_dma[UNM_DUMMY_DMA_SIZE];
- /** RX context creation request and response buffers */
- struct phantom_create_rx_ctx_rqrsp create_rx_ctx;
- /** TX context creation request and response buffers */
- struct phantom_create_tx_ctx_rqrsp create_tx_ctx;
-};
-
-/** A Phantom NIC */
-struct phantom_nic {
- /** BAR 0 */
- void *bar0;
- /** Current CRB window */
- unsigned long crb_window;
- /** CRB window access method */
- unsigned long ( *crb_access ) ( struct phantom_nic *phantom,
- unsigned long reg );
-
- /** Number of ports */
- int num_ports;
- /** Per-port network devices */
- struct net_device *netdev[UNM_FLASH_NUM_PORTS];
- /** DMA buffers */
- union phantom_dma_buffer *dma_buf;
-
- /** Flash memory SPI bus */
- struct spi_bus spi_bus;
- /** Flash memory SPI device */
- struct spi_device flash;
/** Last known link state */
uint32_t link_state;
+ /** Link state poll timer */
+ unsigned long link_poll_timer;
+
+
+ /** Non-volatile settings */
+ struct settings settings;
};
/***************************************************************************
@@ -227,21 +205,8 @@ struct phantom_nic {
*/
static unsigned long phantom_crb_access_128m ( struct phantom_nic *phantom,
unsigned long reg ) {
- static const uint32_t reg_window[] = {
- [UNM_CRB_BLK_PCIE] = 0x0000000,
- [UNM_CRB_BLK_CAM] = 0x2000000,
- [UNM_CRB_BLK_ROMUSB] = 0x2000000,
- [UNM_CRB_BLK_TEST] = 0x0000000,
- };
- static const uint32_t reg_bases[] = {
- [UNM_CRB_BLK_PCIE] = 0x6100000,
- [UNM_CRB_BLK_CAM] = 0x6200000,
- [UNM_CRB_BLK_ROMUSB] = 0x7300000,
- [UNM_CRB_BLK_TEST] = 0x6200000,
- };
- unsigned int block = UNM_CRB_BLK ( reg );
- unsigned long offset = UNM_CRB_OFFSET ( reg );
- uint32_t window = reg_window[block];
+ unsigned long offset = ( 0x6000000 + ( reg & 0x1ffffff ) );
+ uint32_t window = ( reg & 0x2000000 );
uint32_t verify_window;
if ( phantom->crb_window != window ) {
@@ -257,7 +222,7 @@ static unsigned long phantom_crb_access_128m ( struct phantom_nic *phantom,
phantom->crb_window = window;
}
- return ( reg_bases[block] + offset );
+ return offset;
}
/**
@@ -269,21 +234,8 @@ static unsigned long phantom_crb_access_128m ( struct phantom_nic *phantom,
*/
static unsigned long phantom_crb_access_32m ( struct phantom_nic *phantom,
unsigned long reg ) {
- static const uint32_t reg_window[] = {
- [UNM_CRB_BLK_PCIE] = 0x0000000,
- [UNM_CRB_BLK_CAM] = 0x2000000,
- [UNM_CRB_BLK_ROMUSB] = 0x2000000,
- [UNM_CRB_BLK_TEST] = 0x0000000,
- };
- static const uint32_t reg_bases[] = {
- [UNM_CRB_BLK_PCIE] = 0x0100000,
- [UNM_CRB_BLK_CAM] = 0x0200000,
- [UNM_CRB_BLK_ROMUSB] = 0x1300000,
- [UNM_CRB_BLK_TEST] = 0x0200000,
- };
- unsigned int block = UNM_CRB_BLK ( reg );
- unsigned long offset = UNM_CRB_OFFSET ( reg );
- uint32_t window = reg_window[block];
+ unsigned long offset = ( reg & 0x1ffffff );
+ uint32_t window = ( reg & 0x2000000 );
uint32_t verify_window;
if ( phantom->crb_window != window ) {
@@ -299,7 +251,7 @@ static unsigned long phantom_crb_access_32m ( struct phantom_nic *phantom,
phantom->crb_window = window;
}
- return ( reg_bases[block] + offset );
+ return offset;
}
/**
@@ -311,31 +263,54 @@ static unsigned long phantom_crb_access_32m ( struct phantom_nic *phantom,
*/
static unsigned long phantom_crb_access_2m ( struct phantom_nic *phantom,
unsigned long reg ) {
- static const uint32_t reg_window_hi[] = {
- [UNM_CRB_BLK_PCIE] = 0x77300000,
- [UNM_CRB_BLK_CAM] = 0x41600000,
- [UNM_CRB_BLK_ROMUSB] = 0x42100000,
- [UNM_CRB_BLK_TEST] = 0x29500000,
+ static const struct {
+ uint8_t block;
+ uint16_t window_hi;
+ } reg_window_hi[] = {
+ { UNM_CRB_BLK_PCIE, 0x773 },
+ { UNM_CRB_BLK_CAM, 0x416 },
+ { UNM_CRB_BLK_ROMUSB, 0x421 },
+ { UNM_CRB_BLK_TEST, 0x295 },
+ { UNM_CRB_BLK_PEG_0, 0x340 },
+ { UNM_CRB_BLK_PEG_1, 0x341 },
+ { UNM_CRB_BLK_PEG_2, 0x342 },
+ { UNM_CRB_BLK_PEG_3, 0x343 },
+ { UNM_CRB_BLK_PEG_4, 0x34b },
};
unsigned int block = UNM_CRB_BLK ( reg );
unsigned long offset = UNM_CRB_OFFSET ( reg );
- uint32_t window = ( reg_window_hi[block] | ( offset & 0x000f0000 ) );
+ uint32_t window;
uint32_t verify_window;
+ unsigned int i;
- if ( phantom->crb_window != window ) {
+ for ( i = 0 ; i < ( sizeof ( reg_window_hi ) /
+ sizeof ( reg_window_hi[0] ) ) ; i++ ) {
- /* Write to the CRB window register */
- writel ( window, phantom->bar0 + UNM_2M_CRB_WINDOW );
+ if ( reg_window_hi[i].block != block )
+ continue;
- /* Ensure that the write has reached the card */
- verify_window = readl ( phantom->bar0 + UNM_2M_CRB_WINDOW );
- assert ( verify_window == window );
+ window = ( ( reg_window_hi[i].window_hi << 20 ) |
+ ( offset & 0x000f0000 ) );
- /* Record new window */
- phantom->crb_window = window;
+ if ( phantom->crb_window != window ) {
+
+ /* Write to the CRB window register */
+ writel ( window, phantom->bar0 + UNM_2M_CRB_WINDOW );
+
+ /* Ensure that the write has reached the card */
+ verify_window = readl ( phantom->bar0 +
+ UNM_2M_CRB_WINDOW );
+ assert ( verify_window == window );
+
+ /* Record new window */
+ phantom->crb_window = window;
+ }
+
+ return ( 0x1e0000 + ( offset & 0xffff ) );
}
- return ( 0x1e0000 + ( offset & 0xffff ) );
+ assert ( 0 );
+ return 0;
}
/**
@@ -401,8 +376,9 @@ static inline void phantom_write_hilo ( struct phantom_nic *phantom,
* @v buf 8-byte buffer to fill
* @ret rc Return status code
*/
-static int phantom_read_test_mem ( struct phantom_nic *phantom,
- uint64_t offset, uint32_t buf[2] ) {
+static int phantom_read_test_mem_block ( struct phantom_nic *phantom,
+ unsigned long offset,
+ uint32_t buf[2] ) {
unsigned int retries;
uint32_t test_control;
@@ -429,28 +405,57 @@ static int phantom_read_test_mem ( struct phantom_nic *phantom,
}
/**
+ * Read single byte from Phantom test memory
+ *
+ * @v phantom Phantom NIC
+ * @v offset Offset within test memory
+ * @ret byte Byte read, or negative error
+ */
+static int phantom_read_test_mem ( struct phantom_nic *phantom,
+ unsigned long offset ) {
+ static union {
+ uint8_t bytes[8];
+ uint32_t dwords[2];
+ } cache;
+ static unsigned long cache_offset = -1UL;
+ unsigned long sub_offset;
+ int rc;
+
+ sub_offset = ( offset & ( sizeof ( cache ) - 1 ) );
+ offset = ( offset & ~( sizeof ( cache ) - 1 ) );
+
+ if ( cache_offset != offset ) {
+ if ( ( rc = phantom_read_test_mem_block ( phantom, offset,
+ cache.dwords )) !=0 )
+ return rc;
+ cache_offset = offset;
+ }
+
+ return cache.bytes[sub_offset];
+}
+
+/**
* Dump Phantom firmware dmesg log
*
* @v phantom Phantom NIC
* @v log Log number
+ * @v max_lines Maximum number of lines to show, or -1 to show all
+ * @ret rc Return status code
*/
-static void phantom_dmesg ( struct phantom_nic *phantom, unsigned int log ) {
+static int phantom_dmesg ( struct phantom_nic *phantom, unsigned int log,
+ unsigned int max_lines ) {
uint32_t head;
uint32_t tail;
uint32_t len;
uint32_t sig;
uint32_t offset;
- union {
- uint8_t bytes[8];
- uint32_t dwords[2];
- } buf;
- unsigned int i;
- int rc;
+ int byte;
/* Optimise out for non-debug builds */
if ( ! DBG_LOG )
- return;
+ return 0;
+ /* Locate log */
head = phantom_readl ( phantom, UNM_CAM_RAM_DMESG_HEAD ( log ) );
len = phantom_readl ( phantom, UNM_CAM_RAM_DMESG_LEN ( log ) );
tail = phantom_readl ( phantom, UNM_CAM_RAM_DMESG_TAIL ( log ) );
@@ -463,165 +468,37 @@ static void phantom_dmesg ( struct phantom_nic *phantom, unsigned int log ) {
sig, UNM_CAM_RAM_DMESG_SIG_MAGIC );
}
- for ( offset = head ; offset < tail ; offset += 8 ) {
- if ( ( rc = phantom_read_test_mem ( phantom, offset,
- buf.dwords ) ) != 0 ) {
- DBGC ( phantom, "Phantom %p could not read from test "
- "memory: %s\n", phantom, strerror ( rc ) );
+ /* Locate start of last (max_lines) lines */
+ for ( offset = tail ; offset > head ; offset-- ) {
+ if ( ( byte = phantom_read_test_mem ( phantom,
+ ( offset - 1 ) ) ) < 0 )
+ return byte;
+ if ( ( byte == '\n' ) && ( max_lines-- == 0 ) )
break;
- }
- for ( i = 0 ; ( ( i < sizeof ( buf ) ) &&
- ( offset + i ) < tail ) ; i++ ) {
- DBG ( "%c", buf.bytes[i] );
- }
+ }
+
+ /* Print lines */
+ for ( ; offset < tail ; offset++ ) {
+ if ( ( byte = phantom_read_test_mem ( phantom, offset ) ) < 0 )
+ return byte;
+ DBG ( "%c", byte );
}
DBG ( "\n" );
+ return 0;
}
/**
* Dump Phantom firmware dmesg logs
*
* @v phantom Phantom NIC
+ * @v max_lines Maximum number of lines to show, or -1 to show all
*/
static void __attribute__ (( unused ))
-phantom_dmesg_all ( struct phantom_nic *phantom ) {
+phantom_dmesg_all ( struct phantom_nic *phantom, unsigned int max_lines ) {
unsigned int i;
for ( i = 0 ; i < UNM_CAM_RAM_NUM_DMESG_BUFFERS ; i++ )
- phantom_dmesg ( phantom, i );
-}
-
-/***************************************************************************
- *
- * SPI bus access (for flash memory)
- *
- */
-
-/**
- * Acquire Phantom SPI lock
- *
- * @v phantom Phantom NIC
- * @ret rc Return status code
- */
-static int phantom_spi_lock ( struct phantom_nic *phantom ) {
- unsigned int retries;
- uint32_t pcie_sem2_lock;
-
- for ( retries = 0 ; retries < PHN_SPI_LOCK_TIMEOUT_MS ; retries++ ) {
- pcie_sem2_lock = phantom_readl ( phantom, UNM_PCIE_SEM2_LOCK );
- if ( pcie_sem2_lock != 0 )
- return 0;
- mdelay ( 1 );
- }
-
- DBGC ( phantom, "Phantom %p timed out waiting for SPI lock\n",
- phantom );
- return -ETIMEDOUT;
-}
-
-/**
- * Wait for Phantom SPI command to complete
- *
- * @v phantom Phantom NIC
- * @ret rc Return status code
- */
-static int phantom_spi_wait ( struct phantom_nic *phantom ) {
- unsigned int retries;
- uint32_t glb_status;
-
- for ( retries = 0 ; retries < PHN_SPI_CMD_TIMEOUT_MS ; retries++ ) {
- glb_status = phantom_readl ( phantom, UNM_ROMUSB_GLB_STATUS );
- if ( glb_status & UNM_ROMUSB_GLB_STATUS_ROM_DONE )
- return 0;
- mdelay ( 1 );
- }
-
- DBGC ( phantom, "Phantom %p timed out waiting for SPI command\n",
- phantom );
- return -ETIMEDOUT;
-}
-
-/**
- * Release Phantom SPI lock
- *
- * @v phantom Phantom NIC
- */
-static void phantom_spi_unlock ( struct phantom_nic *phantom ) {
- phantom_readl ( phantom, UNM_PCIE_SEM2_UNLOCK );
-}
-
-/**
- * Read/write data via Phantom SPI bus
- *
- * @v bus SPI bus
- * @v device SPI device
- * @v command Command
- * @v address Address to read/write (<0 for no address)
- * @v data_out TX data buffer (or NULL)
- * @v data_in RX data buffer (or NULL)
- * @v len Length of data buffer(s)
- * @ret rc Return status code
- */
-static int phantom_spi_rw ( struct spi_bus *bus,
- struct spi_device *device,
- unsigned int command, int address,
- const void *data_out, void *data_in,
- size_t len ) {
- struct phantom_nic *phantom =
- container_of ( bus, struct phantom_nic, spi_bus );
- uint32_t data;
- int rc;
-
- DBGCP ( phantom, "Phantom %p SPI command %x at %x+%zx\n",
- phantom, command, address, len );
- if ( data_out )
- DBGCP_HDA ( phantom, address, data_out, len );
-
- /* We support only exactly 4-byte reads */
- if ( len != UNM_SPI_BLKSIZE ) {
- DBGC ( phantom, "Phantom %p invalid SPI length %zx\n",
- phantom, len );
- return -EINVAL;
- }
-
- /* Acquire SPI lock */
- if ( ( rc = phantom_spi_lock ( phantom ) ) != 0 )
- goto err_lock;
-
- /* Issue SPI command as per the PRM */
- if ( data_out ) {
- memcpy ( &data, data_out, sizeof ( data ) );
- phantom_writel ( phantom, data, UNM_ROMUSB_ROM_WDATA );
- }
- phantom_writel ( phantom, address, UNM_ROMUSB_ROM_ADDRESS );
- phantom_writel ( phantom, ( device->address_len / 8 ),
- UNM_ROMUSB_ROM_ABYTE_CNT );
- udelay ( 100 ); /* according to PRM */
- phantom_writel ( phantom, 0, UNM_ROMUSB_ROM_DUMMY_BYTE_CNT );
- phantom_writel ( phantom, command, UNM_ROMUSB_ROM_INSTR_OPCODE );
-
- /* Wait for SPI command to complete */
- if ( ( rc = phantom_spi_wait ( phantom ) ) != 0 )
- goto err_wait;
-
- /* Reset address byte count and dummy byte count, because the
- * PRM asks us to.
- */
- phantom_writel ( phantom, 0, UNM_ROMUSB_ROM_ABYTE_CNT );
- udelay ( 100 ); /* according to PRM */
- phantom_writel ( phantom, 0, UNM_ROMUSB_ROM_DUMMY_BYTE_CNT );
-
- /* Read data, if applicable */
- if ( data_in ) {
- data = phantom_readl ( phantom, UNM_ROMUSB_ROM_RDATA );
- memcpy ( data_in, &data, sizeof ( data ) );
- DBGCP_HDA ( phantom, address, data_in, len );
- }
-
- err_wait:
- phantom_spi_unlock ( phantom );
- err_lock:
- return rc;
+ phantom_dmesg ( phantom, i, max_lines );
}
/***************************************************************************
@@ -665,26 +542,24 @@ static int phantom_wait_for_cmd ( struct phantom_nic *phantom ) {
/**
* Issue command to firmware
*
- * @v phantom_port Phantom NIC port
+ * @v phantom Phantom NIC
* @v command Firmware command
* @v arg1 Argument 1
* @v arg2 Argument 2
* @v arg3 Argument 3
* @ret rc Return status code
*/
-static int phantom_issue_cmd ( struct phantom_nic_port *phantom_port,
+static int phantom_issue_cmd ( struct phantom_nic *phantom,
uint32_t command, uint32_t arg1, uint32_t arg2,
uint32_t arg3 ) {
- struct phantom_nic *phantom = phantom_port->phantom;
uint32_t signature;
int rc;
/* Issue command */
- signature = NX_CDRP_SIGNATURE_MAKE ( phantom_port->port,
+ signature = NX_CDRP_SIGNATURE_MAKE ( phantom->port,
NXHAL_VERSION );
- DBGC2 ( phantom, "Phantom %p port %d issuing command %08lx (%08lx, "
- "%08lx, %08lx)\n", phantom, phantom_port->port,
- command, arg1, arg2, arg3 );
+ DBGC2 ( phantom, "Phantom %p issuing command %08lx (%08lx, %08lx, "
+ "%08lx)\n", phantom, command, arg1, arg2, arg3 );
phantom_writel ( phantom, signature, UNM_NIC_REG_NX_SIGN );
phantom_writel ( phantom, arg1, UNM_NIC_REG_NX_ARG1 );
phantom_writel ( phantom, arg2, UNM_NIC_REG_NX_ARG2 );
@@ -705,36 +580,41 @@ static int phantom_issue_cmd ( struct phantom_nic_port *phantom_port,
/**
* Issue buffer-format command to firmware
*
- * @v phantom_port Phantom NIC port
+ * @v phantom Phantom NIC
* @v command Firmware command
* @v buffer Buffer to pass to firmware
* @v len Length of buffer
* @ret rc Return status code
*/
-static int phantom_issue_buf_cmd ( struct phantom_nic_port *phantom_port,
+static int phantom_issue_buf_cmd ( struct phantom_nic *phantom,
uint32_t command, void *buffer,
size_t len ) {
uint64_t physaddr;
physaddr = virt_to_bus ( buffer );
- return phantom_issue_cmd ( phantom_port, command, ( physaddr >> 32 ),
+ return phantom_issue_cmd ( phantom, command, ( physaddr >> 32 ),
( physaddr & 0xffffffffUL ), len );
}
/**
* Create Phantom RX context
*
- * @v phantom_port Phantom NIC port
+ * @v phantom Phantom NIC
* @ret rc Return status code
*/
-static int phantom_create_rx_ctx ( struct phantom_nic_port *phantom_port ) {
- struct phantom_nic *phantom = phantom_port->phantom;
+static int phantom_create_rx_ctx ( struct phantom_nic *phantom ) {
struct phantom_create_rx_ctx_rqrsp *buf;
int rc;
+
+ /* Allocate context creation buffer */
+ buf = malloc_dma ( sizeof ( *buf ), UNM_DMA_BUFFER_ALIGN );
+ if ( ! buf ) {
+ rc = -ENOMEM;
+ goto out;
+ }
+ memset ( buf, 0, sizeof ( *buf ) );
/* Prepare request */
- buf = &phantom->dma_buf->create_rx_ctx;
- memset ( buf, 0, sizeof ( *buf ) );
buf->hostrq.rx_ctx.host_rsp_dma_addr =
cpu_to_le64 ( virt_to_bus ( &buf->cardrsp ) );
buf->hostrq.rx_ctx.capabilities[0] =
@@ -749,197 +629,194 @@ static int phantom_create_rx_ctx ( struct phantom_nic_port *phantom_port ) {
buf->hostrq.rx_ctx.num_rds_rings = cpu_to_le16 ( 1 );
buf->hostrq.rx_ctx.num_sds_rings = cpu_to_le16 ( 1 );
buf->hostrq.rds.host_phys_addr =
- cpu_to_le64 ( virt_to_bus ( phantom_port->desc->rds ) );
+ cpu_to_le64 ( virt_to_bus ( phantom->desc->rds ) );
buf->hostrq.rds.buff_size = cpu_to_le64 ( PHN_RX_BUFSIZE );
buf->hostrq.rds.ring_size = cpu_to_le32 ( PHN_NUM_RDS );
buf->hostrq.rds.ring_kind = cpu_to_le32 ( NX_RDS_RING_TYPE_NORMAL );
buf->hostrq.sds.host_phys_addr =
- cpu_to_le64 ( virt_to_bus ( phantom_port->desc->sds ) );
+ cpu_to_le64 ( virt_to_bus ( phantom->desc->sds ) );
buf->hostrq.sds.ring_size = cpu_to_le32 ( PHN_NUM_SDS );
- DBGC ( phantom, "Phantom %p port %d creating RX context\n",
- phantom, phantom_port->port );
+ DBGC ( phantom, "Phantom %p creating RX context\n", phantom );
DBGC2_HDA ( phantom, virt_to_bus ( &buf->hostrq ),
&buf->hostrq, sizeof ( buf->hostrq ) );
/* Issue request */
- if ( ( rc = phantom_issue_buf_cmd ( phantom_port,
+ if ( ( rc = phantom_issue_buf_cmd ( phantom,
NX_CDRP_CMD_CREATE_RX_CTX,
&buf->hostrq,
sizeof ( buf->hostrq ) ) ) != 0 ) {
- DBGC ( phantom, "Phantom %p port %d could not create RX "
- "context: %s\n",
- phantom, phantom_port->port, strerror ( rc ) );
+ DBGC ( phantom, "Phantom %p could not create RX context: "
+ "%s\n", phantom, strerror ( rc ) );
DBGC ( phantom, "Request:\n" );
DBGC_HDA ( phantom, virt_to_bus ( &buf->hostrq ),
&buf->hostrq, sizeof ( buf->hostrq ) );
DBGC ( phantom, "Response:\n" );
DBGC_HDA ( phantom, virt_to_bus ( &buf->cardrsp ),
&buf->cardrsp, sizeof ( buf->cardrsp ) );
- return rc;
+ goto out;
}
/* Retrieve context parameters */
- phantom_port->rx_context_id =
+ phantom->rx_context_id =
le16_to_cpu ( buf->cardrsp.rx_ctx.context_id );
- phantom_port->rds_producer_crb =
+ phantom->rds_producer_crb =
( UNM_CAM_RAM +
le32_to_cpu ( buf->cardrsp.rds.host_producer_crb ));
- phantom_port->sds_consumer_crb =
+ phantom->sds_consumer_crb =
( UNM_CAM_RAM +
le32_to_cpu ( buf->cardrsp.sds.host_consumer_crb ));
- DBGC ( phantom, "Phantom %p port %d created RX context (id %04x, "
- "port phys %02x virt %02x)\n", phantom, phantom_port->port,
- phantom_port->rx_context_id, buf->cardrsp.rx_ctx.phys_port,
- buf->cardrsp.rx_ctx.virt_port );
+ DBGC ( phantom, "Phantom %p created RX context (id %04x, port phys "
+ "%02x virt %02x)\n", phantom, phantom->rx_context_id,
+ buf->cardrsp.rx_ctx.phys_port, buf->cardrsp.rx_ctx.virt_port );
DBGC2_HDA ( phantom, virt_to_bus ( &buf->cardrsp ),
&buf->cardrsp, sizeof ( buf->cardrsp ) );
- DBGC ( phantom, "Phantom %p port %d RDS producer CRB is %08lx\n",
- phantom, phantom_port->port, phantom_port->rds_producer_crb );
- DBGC ( phantom, "Phantom %p port %d SDS consumer CRB is %08lx\n",
- phantom, phantom_port->port, phantom_port->sds_consumer_crb );
+ DBGC ( phantom, "Phantom %p RDS producer CRB is %08lx\n",
+ phantom, phantom->rds_producer_crb );
+ DBGC ( phantom, "Phantom %p SDS consumer CRB is %08lx\n",
+ phantom, phantom->sds_consumer_crb );
- return 0;
+ out:
+ free_dma ( buf, sizeof ( *buf ) );
+ return rc;
}
/**
* Destroy Phantom RX context
*
- * @v phantom_port Phantom NIC port
+ * @v phantom Phantom NIC
* @ret rc Return status code
*/
-static void phantom_destroy_rx_ctx ( struct phantom_nic_port *phantom_port ) {
- struct phantom_nic *phantom = phantom_port->phantom;
+static void phantom_destroy_rx_ctx ( struct phantom_nic *phantom ) {
int rc;
- DBGC ( phantom, "Phantom %p port %d destroying RX context (id %04x)\n",
- phantom, phantom_port->port, phantom_port->rx_context_id );
+ DBGC ( phantom, "Phantom %p destroying RX context (id %04x)\n",
+ phantom, phantom->rx_context_id );
/* Issue request */
- if ( ( rc = phantom_issue_cmd ( phantom_port,
+ if ( ( rc = phantom_issue_cmd ( phantom,
NX_CDRP_CMD_DESTROY_RX_CTX,
- phantom_port->rx_context_id,
+ phantom->rx_context_id,
NX_DESTROY_CTX_RESET, 0 ) ) != 0 ) {
- DBGC ( phantom, "Phantom %p port %d could not destroy RX "
- "context: %s\n",
- phantom, phantom_port->port, strerror ( rc ) );
+ DBGC ( phantom, "Phantom %p could not destroy RX context: "
+ "%s\n", phantom, strerror ( rc ) );
/* We're probably screwed */
return;
}
/* Clear context parameters */
- phantom_port->rx_context_id = 0;
- phantom_port->rds_producer_crb = 0;
- phantom_port->sds_consumer_crb = 0;
+ phantom->rx_context_id = 0;
+ phantom->rds_producer_crb = 0;
+ phantom->sds_consumer_crb = 0;
/* Reset software counters */
- phantom_port->rds_producer_idx = 0;
- phantom_port->rds_consumer_idx = 0;
- phantom_port->sds_consumer_idx = 0;
+ phantom->rds_producer_idx = 0;
+ phantom->rds_consumer_idx = 0;
+ phantom->sds_consumer_idx = 0;
}
/**
* Create Phantom TX context
*
- * @v phantom_port Phantom NIC port
+ * @v phantom Phantom NIC
* @ret rc Return status code
*/
-static int phantom_create_tx_ctx ( struct phantom_nic_port *phantom_port ) {
- struct phantom_nic *phantom = phantom_port->phantom;
+static int phantom_create_tx_ctx ( struct phantom_nic *phantom ) {
struct phantom_create_tx_ctx_rqrsp *buf;
int rc;
- /* Prepare request */
- buf = &phantom->dma_buf->create_tx_ctx;
+ /* Allocate context creation buffer */
+ buf = malloc_dma ( sizeof ( *buf ), UNM_DMA_BUFFER_ALIGN );
+ if ( ! buf ) {
+ rc = -ENOMEM;
+ goto out;
+ }
memset ( buf, 0, sizeof ( *buf ) );
+
+ /* Prepare request */
buf->hostrq.tx_ctx.host_rsp_dma_addr =
cpu_to_le64 ( virt_to_bus ( &buf->cardrsp ) );
buf->hostrq.tx_ctx.cmd_cons_dma_addr =
- cpu_to_le64 ( virt_to_bus ( &phantom_port->desc->cmd_cons ) );
- buf->hostrq.tx_ctx.dummy_dma_addr =
- cpu_to_le64 ( virt_to_bus ( phantom->dma_buf->dummy_dma ) );
+ cpu_to_le64 ( virt_to_bus ( &phantom->desc->cmd_cons ) );
buf->hostrq.tx_ctx.capabilities[0] =
cpu_to_le32 ( NX_CAP0_LEGACY_CONTEXT | NX_CAP0_LEGACY_MN );
buf->hostrq.tx_ctx.host_int_crb_mode =
cpu_to_le32 ( NX_HOST_INT_CRB_MODE_SHARED );
buf->hostrq.tx_ctx.cds_ring.host_phys_addr =
- cpu_to_le64 ( virt_to_bus ( phantom_port->desc->cds ) );
+ cpu_to_le64 ( virt_to_bus ( phantom->desc->cds ) );
buf->hostrq.tx_ctx.cds_ring.ring_size = cpu_to_le32 ( PHN_NUM_CDS );
- DBGC ( phantom, "Phantom %p port %d creating TX context\n",
- phantom, phantom_port->port );
+ DBGC ( phantom, "Phantom %p creating TX context\n", phantom );
DBGC2_HDA ( phantom, virt_to_bus ( &buf->hostrq ),
&buf->hostrq, sizeof ( buf->hostrq ) );
/* Issue request */
- if ( ( rc = phantom_issue_buf_cmd ( phantom_port,
+ if ( ( rc = phantom_issue_buf_cmd ( phantom,
NX_CDRP_CMD_CREATE_TX_CTX,
&buf->hostrq,
sizeof ( buf->hostrq ) ) ) != 0 ) {
- DBGC ( phantom, "Phantom %p port %d could not create TX "
- "context: %s\n",
- phantom, phantom_port->port, strerror ( rc ) );
+ DBGC ( phantom, "Phantom %p could not create TX context: "
+ "%s\n", phantom, strerror ( rc ) );
DBGC ( phantom, "Request:\n" );
DBGC_HDA ( phantom, virt_to_bus ( &buf->hostrq ),
&buf->hostrq, sizeof ( buf->hostrq ) );
DBGC ( phantom, "Response:\n" );
DBGC_HDA ( phantom, virt_to_bus ( &buf->cardrsp ),
&buf->cardrsp, sizeof ( buf->cardrsp ) );
- return rc;
+ goto out;
}
/* Retrieve context parameters */
- phantom_port->tx_context_id =
+ phantom->tx_context_id =
le16_to_cpu ( buf->cardrsp.tx_ctx.context_id );
- phantom_port->cds_producer_crb =
+ phantom->cds_producer_crb =
( UNM_CAM_RAM +
le32_to_cpu(buf->cardrsp.tx_ctx.cds_ring.host_producer_crb));
- DBGC ( phantom, "Phantom %p port %d created TX context (id %04x, "
- "port phys %02x virt %02x)\n", phantom, phantom_port->port,
- phantom_port->tx_context_id, buf->cardrsp.tx_ctx.phys_port,
- buf->cardrsp.tx_ctx.virt_port );
+ DBGC ( phantom, "Phantom %p created TX context (id %04x, port phys "
+ "%02x virt %02x)\n", phantom, phantom->tx_context_id,
+ buf->cardrsp.tx_ctx.phys_port, buf->cardrsp.tx_ctx.virt_port );
DBGC2_HDA ( phantom, virt_to_bus ( &buf->cardrsp ),
&buf->cardrsp, sizeof ( buf->cardrsp ) );
- DBGC ( phantom, "Phantom %p port %d CDS producer CRB is %08lx\n",
- phantom, phantom_port->port, phantom_port->cds_producer_crb );
+ DBGC ( phantom, "Phantom %p CDS producer CRB is %08lx\n",
+ phantom, phantom->cds_producer_crb );
- return 0;
+ out:
+ free_dma ( buf, sizeof ( *buf ) );
+ return rc;
}
/**
* Destroy Phantom TX context
*
- * @v phantom_port Phantom NIC port
+ * @v phantom Phantom NIC
* @ret rc Return status code
*/
-static void phantom_destroy_tx_ctx ( struct phantom_nic_port *phantom_port ) {
- struct phantom_nic *phantom = phantom_port->phantom;
+static void phantom_destroy_tx_ctx ( struct phantom_nic *phantom ) {
int rc;
- DBGC ( phantom, "Phantom %p port %d destroying TX context (id %04x)\n",
- phantom, phantom_port->port, phantom_port->tx_context_id );
+ DBGC ( phantom, "Phantom %p destroying TX context (id %04x)\n",
+ phantom, phantom->tx_context_id );
/* Issue request */
- if ( ( rc = phantom_issue_cmd ( phantom_port,
+ if ( ( rc = phantom_issue_cmd ( phantom,
NX_CDRP_CMD_DESTROY_TX_CTX,
- phantom_port->tx_context_id,
+ phantom->tx_context_id,
NX_DESTROY_CTX_RESET, 0 ) ) != 0 ) {
- DBGC ( phantom, "Phantom %p port %d could not destroy TX "
- "context: %s\n",
- phantom, phantom_port->port, strerror ( rc ) );
+ DBGC ( phantom, "Phantom %p could not destroy TX context: "
+ "%s\n", phantom, strerror ( rc ) );
/* We're probably screwed */
return;
}
/* Clear context parameters */
- phantom_port->tx_context_id = 0;
- phantom_port->cds_producer_crb = 0;
+ phantom->tx_context_id = 0;
+ phantom->cds_producer_crb = 0;
/* Reset software counters */
- phantom_port->cds_producer_idx = 0;
- phantom_port->cds_consumer_idx = 0;
+ phantom->cds_producer_idx = 0;
+ phantom->cds_consumer_idx = 0;
}
/***************************************************************************
@@ -951,11 +828,10 @@ static void phantom_destroy_tx_ctx ( struct phantom_nic_port *phantom_port ) {
/**
* Allocate Phantom RX descriptor
*
- * @v phantom_port Phantom NIC port
+ * @v phantom Phantom NIC
* @ret index RX descriptor index, or negative error
*/
-static int phantom_alloc_rds ( struct phantom_nic_port *phantom_port ) {
- struct phantom_nic *phantom = phantom_port->phantom;
+static int phantom_alloc_rds ( struct phantom_nic *phantom ) {
unsigned int rds_producer_idx;
unsigned int next_rds_producer_idx;
@@ -965,12 +841,11 @@ static int phantom_alloc_rds ( struct phantom_nic_port *phantom_port ) {
* guaranteed never to be an overestimate of the number of
* descriptors read by the hardware.
*/
- rds_producer_idx = phantom_port->rds_producer_idx;
+ rds_producer_idx = phantom->rds_producer_idx;
next_rds_producer_idx = ( ( rds_producer_idx + 1 ) % PHN_NUM_RDS );
- if ( next_rds_producer_idx == phantom_port->rds_consumer_idx ) {
- DBGC ( phantom, "Phantom %p port %d RDS ring full (index %d "
- "not consumed)\n", phantom, phantom_port->port,
- next_rds_producer_idx );
+ if ( next_rds_producer_idx == phantom->rds_consumer_idx ) {
+ DBGC ( phantom, "Phantom %p RDS ring full (index %d not "
+ "consumed)\n", phantom, next_rds_producer_idx );
return -ENOBUFS;
}
@@ -980,41 +855,38 @@ static int phantom_alloc_rds ( struct phantom_nic_port *phantom_port ) {
/**
* Post Phantom RX descriptor
*
- * @v phantom_port Phantom NIC port
+ * @v phantom Phantom NIC
* @v rds RX descriptor
*/
-static void phantom_post_rds ( struct phantom_nic_port *phantom_port,
+static void phantom_post_rds ( struct phantom_nic *phantom,
struct phantom_rds *rds ) {
- struct phantom_nic *phantom = phantom_port->phantom;
unsigned int rds_producer_idx;
unsigned int next_rds_producer_idx;
struct phantom_rds *entry;
/* Copy descriptor to ring */
- rds_producer_idx = phantom_port->rds_producer_idx;
- entry = &phantom_port->desc->rds[rds_producer_idx];
+ rds_producer_idx = phantom->rds_producer_idx;
+ entry = &phantom->desc->rds[rds_producer_idx];
memcpy ( entry, rds, sizeof ( *entry ) );
- DBGC2 ( phantom, "Phantom %p port %d posting RDS %ld (slot %d):\n",
- phantom, phantom_port->port, NX_GET ( rds, handle ),
- rds_producer_idx );
+ DBGC2 ( phantom, "Phantom %p posting RDS %ld (slot %d):\n",
+ phantom, NX_GET ( rds, handle ), rds_producer_idx );
DBGC2_HDA ( phantom, virt_to_bus ( entry ), entry, sizeof ( *entry ) );
/* Update producer index */
next_rds_producer_idx = ( ( rds_producer_idx + 1 ) % PHN_NUM_RDS );
- phantom_port->rds_producer_idx = next_rds_producer_idx;
+ phantom->rds_producer_idx = next_rds_producer_idx;
wmb();
- phantom_writel ( phantom, phantom_port->rds_producer_idx,
- phantom_port->rds_producer_crb );
+ phantom_writel ( phantom, phantom->rds_producer_idx,
+ phantom->rds_producer_crb );
}
/**
* Allocate Phantom TX descriptor
*
- * @v phantom_port Phantom NIC port
+ * @v phantom Phantom NIC
* @ret index TX descriptor index, or negative error
*/
-static int phantom_alloc_cds ( struct phantom_nic_port *phantom_port ) {
- struct phantom_nic *phantom = phantom_port->phantom;
+static int phantom_alloc_cds ( struct phantom_nic *phantom ) {
unsigned int cds_producer_idx;
unsigned int next_cds_producer_idx;
@@ -1022,12 +894,11 @@ static int phantom_alloc_cds ( struct phantom_nic_port *phantom_port ) {
* in strict order, so we just check for a collision against
* the consumer index.
*/
- cds_producer_idx = phantom_port->cds_producer_idx;
+ cds_producer_idx = phantom->cds_producer_idx;
next_cds_producer_idx = ( ( cds_producer_idx + 1 ) % PHN_NUM_CDS );
- if ( next_cds_producer_idx == phantom_port->cds_consumer_idx ) {
- DBGC ( phantom, "Phantom %p port %d CDS ring full (index %d "
- "not consumed)\n", phantom, phantom_port->port,
- next_cds_producer_idx );
+ if ( next_cds_producer_idx == phantom->cds_consumer_idx ) {
+ DBGC ( phantom, "Phantom %p CDS ring full (index %d not "
+ "consumed)\n", phantom, next_cds_producer_idx );
return -ENOBUFS;
}
@@ -1037,30 +908,29 @@ static int phantom_alloc_cds ( struct phantom_nic_port *phantom_port ) {
/**
* Post Phantom TX descriptor
*
- * @v phantom_port Phantom NIC port
+ * @v phantom Phantom NIC
* @v cds TX descriptor
*/
-static void phantom_post_cds ( struct phantom_nic_port *phantom_port,
+static void phantom_post_cds ( struct phantom_nic *phantom,
union phantom_cds *cds ) {
- struct phantom_nic *phantom = phantom_port->phantom;
unsigned int cds_producer_idx;
unsigned int next_cds_producer_idx;
union phantom_cds *entry;
/* Copy descriptor to ring */
- cds_producer_idx = phantom_port->cds_producer_idx;
- entry = &phantom_port->desc->cds[cds_producer_idx];
+ cds_producer_idx = phantom->cds_producer_idx;
+ entry = &phantom->desc->cds[cds_producer_idx];
memcpy ( entry, cds, sizeof ( *entry ) );
- DBGC2 ( phantom, "Phantom %p port %d posting CDS %d:\n",
- phantom, phantom_port->port, cds_producer_idx );
+ DBGC2 ( phantom, "Phantom %p posting CDS %d:\n",
+ phantom, cds_producer_idx );
DBGC2_HDA ( phantom, virt_to_bus ( entry ), entry, sizeof ( *entry ) );
/* Update producer index */
next_cds_producer_idx = ( ( cds_producer_idx + 1 ) % PHN_NUM_CDS );
- phantom_port->cds_producer_idx = next_cds_producer_idx;
+ phantom->cds_producer_idx = next_cds_producer_idx;
wmb();
- phantom_writel ( phantom, phantom_port->cds_producer_idx,
- phantom_port->cds_producer_crb );
+ phantom_writel ( phantom, phantom->cds_producer_idx,
+ phantom->cds_producer_crb );
}
/***************************************************************************
@@ -1072,19 +942,19 @@ static void phantom_post_cds ( struct phantom_nic_port *phantom_port,
/**
* Add/remove MAC address
*
- * @v phantom_port Phantom NIC port
+ * @v phantom Phantom NIC
* @v ll_addr MAC address to add or remove
* @v opcode MAC request opcode
* @ret rc Return status code
*/
-static int phantom_update_macaddr ( struct phantom_nic_port *phantom_port,
+static int phantom_update_macaddr ( struct phantom_nic *phantom,
const uint8_t *ll_addr,
unsigned int opcode ) {
union phantom_cds cds;
int index;
/* Get descriptor ring entry */
- index = phantom_alloc_cds ( phantom_port );
+ index = phantom_alloc_cds ( phantom );
if ( index < 0 )
return index;
@@ -1094,7 +964,7 @@ static int phantom_update_macaddr ( struct phantom_nic_port *phantom_port,
nic_request.common.opcode, UNM_NIC_REQUEST );
NX_FILL_2 ( &cds, 1,
nic_request.header.opcode, UNM_MAC_EVENT,
- nic_request.header.context_id, phantom_port->port );
+ nic_request.header.context_id, phantom->port );
NX_FILL_7 ( &cds, 2,
nic_request.body.mac_request.opcode, opcode,
nic_request.body.mac_request.mac_addr_0, ll_addr[0],
@@ -1105,7 +975,7 @@ static int phantom_update_macaddr ( struct phantom_nic_port *phantom_port,
nic_request.body.mac_request.mac_addr_5, ll_addr[5] );
/* Post descriptor */
- phantom_post_cds ( phantom_port, &cds );
+ phantom_post_cds ( phantom, &cds );
return 0;
}
@@ -1113,35 +983,33 @@ static int phantom_update_macaddr ( struct phantom_nic_port *phantom_port,
/**
* Add MAC address
*
- * @v phantom_port Phantom NIC port
+ * @v phantom Phantom NIC
* @v ll_addr MAC address to add or remove
* @ret rc Return status code
*/
-static inline int phantom_add_macaddr ( struct phantom_nic_port *phantom_port,
+static inline int phantom_add_macaddr ( struct phantom_nic *phantom,
const uint8_t *ll_addr ) {
- struct phantom_nic *phantom = phantom_port->phantom;
- DBGC ( phantom, "Phantom %p port %d adding MAC address %s\n",
- phantom, phantom_port->port, eth_ntoa ( ll_addr ) );
+ DBGC ( phantom, "Phantom %p adding MAC address %s\n",
+ phantom, eth_ntoa ( ll_addr ) );
- return phantom_update_macaddr ( phantom_port, ll_addr, UNM_MAC_ADD );
+ return phantom_update_macaddr ( phantom, ll_addr, UNM_MAC_ADD );
}
/**
* Remove MAC address
*
- * @v phantom_port Phantom NIC port
+ * @v phantom Phantom NIC
* @v ll_addr MAC address to add or remove
* @ret rc Return status code
*/
-static inline int phantom_del_macaddr ( struct phantom_nic_port *phantom_port,
+static inline int phantom_del_macaddr ( struct phantom_nic *phantom,
const uint8_t *ll_addr ) {
- struct phantom_nic *phantom = phantom_port->phantom;
- DBGC ( phantom, "Phantom %p port %d removing MAC address %s\n",
- phantom, phantom_port->port, eth_ntoa ( ll_addr ) );
+ DBGC ( phantom, "Phantom %p removing MAC address %s\n",
+ phantom, eth_ntoa ( ll_addr ) );
- return phantom_update_macaddr ( phantom_port, ll_addr, UNM_MAC_DEL );
+ return phantom_update_macaddr ( phantom, ll_addr, UNM_MAC_DEL );
}
/***************************************************************************
@@ -1153,14 +1021,12 @@ static inline int phantom_del_macaddr ( struct phantom_nic_port *phantom_port,
/**
* Poll link state
*
- * @v phantom Phantom NIC
+ * @v netdev Network device
*/
-static void phantom_poll_link_state ( struct phantom_nic *phantom ) {
- struct net_device *netdev;
- struct phantom_nic_port *phantom_port;
+static void phantom_poll_link_state ( struct net_device *netdev ) {
+ struct phantom_nic *phantom = netdev_priv ( netdev );
uint32_t xg_state_p3;
unsigned int link;
- int i;
/* Read link state */
xg_state_p3 = phantom_readl ( phantom, UNM_NIC_REG_XG_STATE_P3 );
@@ -1174,28 +1040,22 @@ static void phantom_poll_link_state ( struct phantom_nic *phantom ) {
phantom, xg_state_p3, phantom->link_state );
phantom->link_state = xg_state_p3;
- /* Indicate per-port link state to gPXE */
- for ( i = 0 ; i < phantom->num_ports ; i++ ) {
- netdev = phantom->netdev[i];
- phantom_port = netdev_priv ( netdev );
- link = UNM_NIC_REG_XG_STATE_P3_LINK ( phantom_port->port,
- phantom->link_state );
- switch ( link ) {
- case UNM_NIC_REG_XG_STATE_P3_LINK_UP:
- DBGC ( phantom, "Phantom %p port %d link is up\n",
- phantom, phantom_port->port );
- netdev_link_up ( netdev );
- break;
- case UNM_NIC_REG_XG_STATE_P3_LINK_DOWN:
- DBGC ( phantom, "Phantom %p port %d link is down\n",
- phantom, phantom_port->port );
- netdev_link_down ( netdev );
- break;
- default:
- DBGC ( phantom, "Phantom %p port %d bad link state "
- "%d\n", phantom, phantom_port->port, link );
- break;
- }
+ /* Indicate link state to gPXE */
+ link = UNM_NIC_REG_XG_STATE_P3_LINK ( phantom->port,
+ phantom->link_state );
+ switch ( link ) {
+ case UNM_NIC_REG_XG_STATE_P3_LINK_UP:
+ DBGC ( phantom, "Phantom %p link is up\n", phantom );
+ netdev_link_up ( netdev );
+ break;
+ case UNM_NIC_REG_XG_STATE_P3_LINK_DOWN:
+ DBGC ( phantom, "Phantom %p link is down\n", phantom );
+ netdev_link_down ( netdev );
+ break;
+ default:
+ DBGC ( phantom, "Phantom %p bad link state %d\n",
+ phantom, link );
+ break;
}
}
@@ -1211,7 +1071,7 @@ static void phantom_poll_link_state ( struct phantom_nic *phantom ) {
* @v netdev Net device
*/
static void phantom_refill_rx_ring ( struct net_device *netdev ) {
- struct phantom_nic_port *phantom_port = netdev_priv ( netdev );
+ struct phantom_nic *phantom = netdev_priv ( netdev );
struct io_buffer *iobuf;
struct phantom_rds rds;
unsigned int handle;
@@ -1222,11 +1082,11 @@ static void phantom_refill_rx_ring ( struct net_device *netdev ) {
/* Skip this index if the descriptor has not yet been
* consumed.
*/
- if ( phantom_port->rds_iobuf[handle] != NULL )
+ if ( phantom->rds_iobuf[handle] != NULL )
continue;
/* Allocate descriptor ring entry */
- index = phantom_alloc_rds ( phantom_port );
+ index = phantom_alloc_rds ( phantom );
assert ( PHN_RDS_MAX_FILL < PHN_NUM_RDS );
assert ( index >= 0 ); /* Guaranteed by MAX_FILL < NUM_RDS ) */
@@ -1247,11 +1107,11 @@ static void phantom_refill_rx_ring ( struct net_device *netdev ) {
dma_addr, virt_to_bus ( iobuf->data ) );
/* Record I/O buffer */
- assert ( phantom_port->rds_iobuf[handle] == NULL );
- phantom_port->rds_iobuf[handle] = iobuf;
+ assert ( phantom->rds_iobuf[handle] == NULL );
+ phantom->rds_iobuf[handle] = iobuf;
/* Post descriptor */
- phantom_post_rds ( phantom_port, &rds );
+ phantom_post_rds ( phantom, &rds );
}
}
@@ -1262,24 +1122,24 @@ static void phantom_refill_rx_ring ( struct net_device *netdev ) {
* @ret rc Return status code
*/
static int phantom_open ( struct net_device *netdev ) {
- struct phantom_nic_port *phantom_port = netdev_priv ( netdev );
+ struct phantom_nic *phantom = netdev_priv ( netdev );
int rc;
/* Allocate and zero descriptor rings */
- phantom_port->desc = malloc_dma ( sizeof ( *(phantom_port->desc) ),
+ phantom->desc = malloc_dma ( sizeof ( *(phantom->desc) ),
UNM_DMA_BUFFER_ALIGN );
- if ( ! phantom_port->desc ) {
+ if ( ! phantom->desc ) {
rc = -ENOMEM;
goto err_alloc_desc;
}
- memset ( phantom_port->desc, 0, sizeof ( *(phantom_port->desc) ) );
+ memset ( phantom->desc, 0, sizeof ( *(phantom->desc) ) );
/* Create RX context */
- if ( ( rc = phantom_create_rx_ctx ( phantom_port ) ) != 0 )
+ if ( ( rc = phantom_create_rx_ctx ( phantom ) ) != 0 )
goto err_create_rx_ctx;
/* Create TX context */
- if ( ( rc = phantom_create_tx_ctx ( phantom_port ) ) != 0 )
+ if ( ( rc = phantom_create_tx_ctx ( phantom ) ) != 0 )
goto err_create_tx_ctx;
/* Fill the RX descriptor ring */
@@ -1293,26 +1153,26 @@ static int phantom_open ( struct net_device *netdev ) {
* packets (or, failing that, promiscuous mode), but the
* firmware doesn't currently support this.
*/
- if ( ( rc = phantom_add_macaddr ( phantom_port,
+ if ( ( rc = phantom_add_macaddr ( phantom,
netdev->ll_protocol->ll_broadcast ) ) != 0 )
goto err_add_macaddr_broadcast;
- if ( ( rc = phantom_add_macaddr ( phantom_port,
+ if ( ( rc = phantom_add_macaddr ( phantom,
netdev->ll_addr ) ) != 0 )
goto err_add_macaddr_unicast;
return 0;
- phantom_del_macaddr ( phantom_port, netdev->ll_addr );
+ phantom_del_macaddr ( phantom, netdev->ll_addr );
err_add_macaddr_unicast:
- phantom_del_macaddr ( phantom_port,
+ phantom_del_macaddr ( phantom,
netdev->ll_protocol->ll_broadcast );
err_add_macaddr_broadcast:
- phantom_destroy_tx_ctx ( phantom_port );
+ phantom_destroy_tx_ctx ( phantom );
err_create_tx_ctx:
- phantom_destroy_rx_ctx ( phantom_port );
+ phantom_destroy_rx_ctx ( phantom );
err_create_rx_ctx:
- free_dma ( phantom_port->desc, sizeof ( *(phantom_port->desc) ) );
- phantom_port->desc = NULL;
+ free_dma ( phantom->desc, sizeof ( *(phantom->desc) ) );
+ phantom->desc = NULL;
err_alloc_desc:
return rc;
}
@@ -1323,32 +1183,32 @@ static int phantom_open ( struct net_device *netdev ) {
* @v netdev Net device
*/
static void phantom_close ( struct net_device *netdev ) {
- struct phantom_nic_port *phantom_port = netdev_priv ( netdev );
+ struct phantom_nic *phantom = netdev_priv ( netdev );
struct io_buffer *iobuf;
unsigned int i;
/* Shut down the port */
- phantom_del_macaddr ( phantom_port, netdev->ll_addr );
- phantom_del_macaddr ( phantom_port,
+ phantom_del_macaddr ( phantom, netdev->ll_addr );
+ phantom_del_macaddr ( phantom,
netdev->ll_protocol->ll_broadcast );
- phantom_destroy_tx_ctx ( phantom_port );
- phantom_destroy_rx_ctx ( phantom_port );
- free_dma ( phantom_port->desc, sizeof ( *(phantom_port->desc) ) );
- phantom_port->desc = NULL;
+ phantom_destroy_tx_ctx ( phantom );
+ phantom_destroy_rx_ctx ( phantom );
+ free_dma ( phantom->desc, sizeof ( *(phantom->desc) ) );
+ phantom->desc = NULL;
/* Flush any uncompleted descriptors */
for ( i = 0 ; i < PHN_RDS_MAX_FILL ; i++ ) {
- iobuf = phantom_port->rds_iobuf[i];
+ iobuf = phantom->rds_iobuf[i];
if ( iobuf ) {
free_iob ( iobuf );
- phantom_port->rds_iobuf[i] = NULL;
+ phantom->rds_iobuf[i] = NULL;
}
}
for ( i = 0 ; i < PHN_NUM_CDS ; i++ ) {
- iobuf = phantom_port->cds_iobuf[i];
+ iobuf = phantom->cds_iobuf[i];
if ( iobuf ) {
netdev_tx_complete_err ( netdev, iobuf, -ECANCELED );
- phantom_port->cds_iobuf[i] = NULL;
+ phantom->cds_iobuf[i] = NULL;
}
}
}
@@ -1362,12 +1222,12 @@ static void phantom_close ( struct net_device *netdev ) {
*/
static int phantom_transmit ( struct net_device *netdev,
struct io_buffer *iobuf ) {
- struct phantom_nic_port *phantom_port = netdev_priv ( netdev );
+ struct phantom_nic *phantom = netdev_priv ( netdev );
union phantom_cds cds;
int index;
/* Get descriptor ring entry */
- index = phantom_alloc_cds ( phantom_port );
+ index = phantom_alloc_cds ( phantom );
if ( index < 0 )
return index;
@@ -1378,19 +1238,19 @@ static int phantom_transmit ( struct net_device *netdev,
tx.num_buffers, 1,
tx.length, iob_len ( iobuf ) );
NX_FILL_2 ( &cds, 2,
- tx.port, phantom_port->port,
- tx.context_id, phantom_port->port );
+ tx.port, phantom->port,
+ tx.context_id, phantom->port );
NX_FILL_1 ( &cds, 4,
tx.buffer1_dma_addr, virt_to_bus ( iobuf->data ) );
NX_FILL_1 ( &cds, 5,
tx.buffer1_length, iob_len ( iobuf ) );
/* Record I/O buffer */
- assert ( phantom_port->cds_iobuf[index] == NULL );
- phantom_port->cds_iobuf[index] = iobuf;
+ assert ( phantom->cds_iobuf[index] == NULL );
+ phantom->cds_iobuf[index] = iobuf;
/* Post descriptor */
- phantom_post_cds ( phantom_port, &cds );
+ phantom_post_cds ( phantom, &cds );
return 0;
}
@@ -1401,8 +1261,7 @@ static int phantom_transmit ( struct net_device *netdev,
* @v netdev Network device
*/
static void phantom_poll ( struct net_device *netdev ) {
- struct phantom_nic_port *phantom_port = netdev_priv ( netdev );
- struct phantom_nic *phantom = phantom_port->phantom;
+ struct phantom_nic *phantom = netdev_priv ( netdev );
struct io_buffer *iobuf;
unsigned int cds_consumer_idx;
unsigned int raw_new_cds_consumer_idx;
@@ -1414,33 +1273,33 @@ static void phantom_poll ( struct net_device *netdev ) {
unsigned int sds_opcode;
/* Check for TX completions */
- cds_consumer_idx = phantom_port->cds_consumer_idx;
- raw_new_cds_consumer_idx = phantom_port->desc->cmd_cons;
+ cds_consumer_idx = phantom->cds_consumer_idx;
+ raw_new_cds_consumer_idx = phantom->desc->cmd_cons;
new_cds_consumer_idx = le32_to_cpu ( raw_new_cds_consumer_idx );
while ( cds_consumer_idx != new_cds_consumer_idx ) {
- DBGC2 ( phantom, "Phantom %p port %d CDS %d complete\n",
- phantom, phantom_port->port, cds_consumer_idx );
+ DBGC2 ( phantom, "Phantom %p CDS %d complete\n",
+ phantom, cds_consumer_idx );
/* Completions may be for commands other than TX, so
* there may not always be an associated I/O buffer.
*/
- if ( ( iobuf = phantom_port->cds_iobuf[cds_consumer_idx] ) ) {
+ if ( ( iobuf = phantom->cds_iobuf[cds_consumer_idx] ) ) {
netdev_tx_complete ( netdev, iobuf );
- phantom_port->cds_iobuf[cds_consumer_idx] = NULL;
+ phantom->cds_iobuf[cds_consumer_idx] = NULL;
}
cds_consumer_idx = ( ( cds_consumer_idx + 1 ) % PHN_NUM_CDS );
- phantom_port->cds_consumer_idx = cds_consumer_idx;
+ phantom->cds_consumer_idx = cds_consumer_idx;
}
/* Check for received packets */
- rds_consumer_idx = phantom_port->rds_consumer_idx;
- sds_consumer_idx = phantom_port->sds_consumer_idx;
+ rds_consumer_idx = phantom->rds_consumer_idx;
+ sds_consumer_idx = phantom->sds_consumer_idx;
while ( 1 ) {
- sds = &phantom_port->desc->sds[sds_consumer_idx];
+ sds = &phantom->desc->sds[sds_consumer_idx];
if ( NX_GET ( sds, owner ) == 0 )
break;
- DBGC2 ( phantom, "Phantom %p port %d SDS %d status:\n",
- phantom, phantom_port->port, sds_consumer_idx );
+ DBGC2 ( phantom, "Phantom %p SDS %d status:\n",
+ phantom, sds_consumer_idx );
DBGC2_HDA ( phantom, virt_to_bus ( sds ), sds, sizeof (*sds) );
/* Check received opcode */
@@ -1452,24 +1311,23 @@ static void phantom_poll ( struct net_device *netdev ) {
* descriptor has been written.
*/
if ( NX_GET ( sds, total_length ) == 0 ) {
- DBGC ( phantom, "Phantom %p port %d SDS %d "
- "incomplete; deferring\n", phantom,
- phantom_port->port, sds_consumer_idx );
+ DBGC ( phantom, "Phantom %p SDS %d "
+ "incomplete; deferring\n",
+ phantom, sds_consumer_idx );
/* Leave for next poll() */
break;
}
/* Process received packet */
sds_handle = NX_GET ( sds, handle );
- iobuf = phantom_port->rds_iobuf[sds_handle];
+ iobuf = phantom->rds_iobuf[sds_handle];
assert ( iobuf != NULL );
iob_put ( iobuf, NX_GET ( sds, total_length ) );
iob_pull ( iobuf, NX_GET ( sds, pkt_offset ) );
- DBGC2 ( phantom, "Phantom %p port %d RDS %d "
- "complete\n",
- phantom, phantom_port->port, sds_handle );
+ DBGC2 ( phantom, "Phantom %p RDS %d complete\n",
+ phantom, sds_handle );
netdev_rx ( netdev, iobuf );
- phantom_port->rds_iobuf[sds_handle] = NULL;
+ phantom->rds_iobuf[sds_handle] = NULL;
/* Update RDS consumer counter. This is a
* lower bound for the number of descriptors
@@ -1480,13 +1338,12 @@ static void phantom_poll ( struct net_device *netdev ) {
*/
rds_consumer_idx =
( ( rds_consumer_idx + 1 ) % PHN_NUM_RDS );
- phantom_port->rds_consumer_idx = rds_consumer_idx;
+ phantom->rds_consumer_idx = rds_consumer_idx;
} else {
- DBGC ( phantom, "Phantom %p port %d unexpected SDS "
- "opcode %02x\n",
- phantom, phantom_port->port, sds_opcode );
+ DBGC ( phantom, "Phantom %p unexpected SDS opcode "
+ "%02x\n", phantom, sds_opcode );
DBGC_HDA ( phantom, virt_to_bus ( sds ),
sds, sizeof ( *sds ) );
}
@@ -1496,20 +1353,20 @@ static void phantom_poll ( struct net_device *netdev ) {
/* Update SDS consumer index */
sds_consumer_idx = ( ( sds_consumer_idx + 1 ) % PHN_NUM_SDS );
- phantom_port->sds_consumer_idx = sds_consumer_idx;
+ phantom->sds_consumer_idx = sds_consumer_idx;
wmb();
- phantom_writel ( phantom, phantom_port->sds_consumer_idx,
- phantom_port->sds_consumer_crb );
+ phantom_writel ( phantom, phantom->sds_consumer_idx,
+ phantom->sds_consumer_crb );
}
/* Refill the RX descriptor ring */
phantom_refill_rx_ring ( netdev );
/* Occasionally poll the link state */
- if ( phantom_port->link_poll_timer-- == 0 ) {
- phantom_poll_link_state ( phantom );
+ if ( phantom->link_poll_timer-- == 0 ) {
+ phantom_poll_link_state ( netdev );
/* Reset the link poll timer */
- phantom_port->link_poll_timer = PHN_LINK_POLL_FREQUENCY;
+ phantom->link_poll_timer = PHN_LINK_POLL_FREQUENCY;
}
}
@@ -1520,9 +1377,8 @@ static void phantom_poll ( struct net_device *netdev ) {
* @v enable Interrupts should be enabled
*/
static void phantom_irq ( struct net_device *netdev, int enable ) {
- struct phantom_nic_port *phantom_port = netdev_priv ( netdev );
- struct phantom_nic *phantom = phantom_port->phantom;
- static const unsigned long sw_int_mask_reg[UNM_FLASH_NUM_PORTS] = {
+ struct phantom_nic *phantom = netdev_priv ( netdev );
+ static const unsigned long sw_int_mask_reg[PHN_MAX_NUM_PORTS] = {
UNM_NIC_REG_SW_INT_MASK_0,
UNM_NIC_REG_SW_INT_MASK_1,
UNM_NIC_REG_SW_INT_MASK_2,
@@ -1531,7 +1387,7 @@ static void phantom_irq ( struct net_device *netdev, int enable ) {
phantom_writel ( phantom,
( enable ? 1 : 0 ),
- sw_int_mask_reg[phantom_port->port] );
+ sw_int_mask_reg[phantom->port] );
}
/** Phantom net device operations */
@@ -1543,6 +1399,336 @@ static struct net_device_operations phantom_operations = {
.irq = phantom_irq,
};
+/***************************************************************************
+ *
+ * CLP settings
+ *
+ */
+
+/** Phantom CLP settings tag magic */
+#define PHN_CLP_TAG_MAGIC 0xc19c1900UL
+
+/** Phantom CLP settings tag magic mask */
+#define PHN_CLP_TAG_MAGIC_MASK 0xffffff00UL
+
+/** Phantom CLP data
+ *
+ */
+union phantom_clp_data {
+ /** Data bytes
+ *
+ * This field is right-aligned; if only N bytes are present
+ * then bytes[0]..bytes[7-N] should be zero, and the data
+ * should be in bytes[7-N+1] to bytes[7];
+ */
+ uint8_t bytes[8];
+ /** Dwords for the CLP interface */
+ struct {
+ /** High dword, in network byte order */
+ uint32_t hi;
+ /** Low dword, in network byte order */
+ uint32_t lo;
+ } dwords;
+};
+#define PHN_CLP_BLKSIZE ( sizeof ( union phantom_clp_data ) )
+
+/**
+ * Wait for Phantom CLP command to complete
+ *
+ * @v phantom Phantom NIC
+ * @ret rc Return status code
+ */
+static int phantom_clp_wait ( struct phantom_nic *phantom ) {
+ unsigned int retries;
+ uint32_t status;
+
+ for ( retries = 0 ; retries < PHN_CLP_CMD_TIMEOUT_MS ; retries++ ) {
+ status = phantom_readl ( phantom, UNM_CAM_RAM_CLP_STATUS );
+ if ( status & UNM_CAM_RAM_CLP_STATUS_DONE )
+ return 0;
+ mdelay ( 1 );
+ }
+
+ DBGC ( phantom, "Phantom %p timed out waiting for CLP command\n",
+ phantom );
+ return -ETIMEDOUT;
+}
+
+/**
+ * Issue Phantom CLP command
+ *
+ * @v phantom Phantom NIC
+ * @v port Virtual port number
+ * @v opcode Opcode
+ * @v data_in Data in, or NULL
+ * @v data_out Data out, or NULL
+ * @v offset Offset within data
+ * @v len Data buffer length
+ * @ret len Total transfer length (for reads), or negative error
+ */
+static int phantom_clp_cmd ( struct phantom_nic *phantom, unsigned int port,
+ unsigned int opcode, const void *data_in,
+ void *data_out, size_t offset, size_t len ) {
+ union phantom_clp_data data;
+ unsigned int index = ( offset / sizeof ( data ) );
+ unsigned int last = 0;
+ size_t in_frag_len;
+ uint8_t *in_frag;
+ uint32_t command;
+ uint32_t status;
+ size_t read_len;
+ unsigned int error;
+ size_t out_frag_len;
+ uint8_t *out_frag;
+ int rc;
+
+ /* Sanity checks */
+ assert ( ( offset % sizeof ( data ) ) == 0 );
+ if ( len > 255 ) {
+ DBGC ( phantom, "Phantom %p invalid CLP length %zd\n",
+ phantom, len );
+ return -EINVAL;
+ }
+
+ /* Check that CLP interface is ready */
+ if ( ( rc = phantom_clp_wait ( phantom ) ) != 0 )
+ return rc;
+
+ /* Copy data in */
+ memset ( &data, 0, sizeof ( data ) );
+ if ( data_in ) {
+ assert ( offset < len );
+ in_frag_len = ( len - offset );
+ if ( in_frag_len > sizeof ( data ) ) {
+ in_frag_len = sizeof ( data );
+ } else {
+ last = 1;
+ }
+ in_frag = &data.bytes[ sizeof ( data ) - in_frag_len ];
+ memcpy ( in_frag, ( data_in + offset ), in_frag_len );
+ phantom_writel ( phantom, be32_to_cpu ( data.dwords.lo ),
+ UNM_CAM_RAM_CLP_DATA_LO );
+ phantom_writel ( phantom, be32_to_cpu ( data.dwords.hi ),
+ UNM_CAM_RAM_CLP_DATA_HI );
+ }
+
+ /* Issue CLP command */
+ command = ( ( index << 24 ) | ( ( data_in ? len : 0 ) << 16 ) |
+ ( port << 8 ) | ( last << 7 ) | ( opcode << 0 ) );
+ phantom_writel ( phantom, command, UNM_CAM_RAM_CLP_COMMAND );
+ mb();
+ phantom_writel ( phantom, UNM_CAM_RAM_CLP_STATUS_START,
+ UNM_CAM_RAM_CLP_STATUS );
+
+ /* Wait for command to complete */
+ if ( ( rc = phantom_clp_wait ( phantom ) ) != 0 )
+ return rc;
+
+ /* Get command status */
+ status = phantom_readl ( phantom, UNM_CAM_RAM_CLP_STATUS );
+ read_len = ( ( status >> 16 ) & 0xff );
+ error = ( ( status >> 8 ) & 0xff );
+ if ( error ) {
+ DBGC ( phantom, "Phantom %p CLP command error %02x\n",
+ phantom, error );
+ return -EIO;
+ }
+
+ /* Copy data out */
+ if ( data_out ) {
+ data.dwords.lo = cpu_to_be32 ( phantom_readl ( phantom,
+ UNM_CAM_RAM_CLP_DATA_LO ) );
+ data.dwords.hi = cpu_to_be32 ( phantom_readl ( phantom,
+ UNM_CAM_RAM_CLP_DATA_HI ) );
+ out_frag_len = ( read_len - offset );
+ if ( out_frag_len > sizeof ( data ) )
+ out_frag_len = sizeof ( data );
+ out_frag = &data.bytes[ sizeof ( data ) - out_frag_len ];
+ if ( out_frag_len > ( len - offset ) )
+ out_frag_len = ( len - offset );
+ memcpy ( ( data_out + offset ), out_frag, out_frag_len );
+ }
+
+ return read_len;
+}
+
+/**
+ * Store Phantom CLP setting
+ *
+ * @v phantom Phantom NIC
+ * @v port Virtual port number
+ * @v setting Setting number
+ * @v data Data buffer
+ * @v len Length of data buffer
+ * @ret rc Return status code
+ */
+static int phantom_clp_store ( struct phantom_nic *phantom, unsigned int port,
+ unsigned int setting, const void *data,
+ size_t len ) {
+ unsigned int opcode = setting;
+ size_t offset;
+ int rc;
+
+ for ( offset = 0 ; offset < len ; offset += PHN_CLP_BLKSIZE ) {
+ if ( ( rc = phantom_clp_cmd ( phantom, port, opcode, data,
+ NULL, offset, len ) ) < 0 )
+ return rc;
+ }
+ return 0;
+}
+
+/**
+ * Fetch Phantom CLP setting
+ *
+ * @v phantom Phantom NIC
+ * @v port Virtual port number
+ * @v setting Setting number
+ * @v data Data buffer
+ * @v len Length of data buffer
+ * @ret len Length of setting, or negative error
+ */
+static int phantom_clp_fetch ( struct phantom_nic *phantom, unsigned int port,
+ unsigned int setting, void *data, size_t len ) {
+ unsigned int opcode = ( setting + 1 );
+ size_t offset = 0;
+ int read_len;
+
+ while ( 1 ) {
+ read_len = phantom_clp_cmd ( phantom, port, opcode, NULL,
+ data, offset, len );
+ if ( read_len < 0 )
+ return read_len;
+ offset += PHN_CLP_BLKSIZE;
+ if ( offset >= ( unsigned ) read_len )
+ break;
+ if ( offset >= len )
+ break;
+ }
+ return read_len;
+}
+
+/** A Phantom CLP setting */
+struct phantom_clp_setting {
+ /** gPXE setting */
+ struct setting *setting;
+ /** Setting number */
+ unsigned int clp_setting;
+};
+
+/** Phantom CLP settings */
+static struct phantom_clp_setting clp_settings[] = {
+ { &mac_setting, 0x01 },
+};
+
+/**
+ * Find Phantom CLP setting
+ *
+ * @v setting gPXE setting
+ * @v clp_setting Setting number, or 0 if not found
+ */
+static unsigned int
+phantom_clp_setting ( struct phantom_nic *phantom, struct setting *setting ) {
+ struct phantom_clp_setting *clp_setting;
+ unsigned int i;
+
+ /* Search the list of explicitly-defined settings */
+ for ( i = 0 ; i < ( sizeof ( clp_settings ) /
+ sizeof ( clp_settings[0] ) ) ; i++ ) {
+ clp_setting = &clp_settings[i];
+ if ( setting_cmp ( setting, clp_setting->setting ) == 0 )
+ return clp_setting->clp_setting;
+ }
+
+ /* Allow for use of numbered settings */
+ if ( ( setting->tag & PHN_CLP_TAG_MAGIC_MASK ) == PHN_CLP_TAG_MAGIC )
+ return ( setting->tag & ~PHN_CLP_TAG_MAGIC_MASK );
+
+ DBGC2 ( phantom, "Phantom %p has no \"%s\" setting\n",
+ phantom, setting->name );
+
+ return 0;
+}
+
+/**
+ * Store Phantom CLP setting
+ *
+ * @v settings Settings block
+ * @v setting Setting to store
+ * @v data Setting data, or NULL to clear setting
+ * @v len Length of setting data
+ * @ret rc Return status code
+ */
+static int phantom_store_setting ( struct settings *settings,
+ struct setting *setting,
+ const void *data, size_t len ) {
+ struct phantom_nic *phantom =
+ container_of ( settings, struct phantom_nic, settings );
+ unsigned int clp_setting;
+ int rc;
+
+ /* Find Phantom setting equivalent to gPXE setting */
+ clp_setting = phantom_clp_setting ( phantom, setting );
+ if ( ! clp_setting )
+ return -ENOTSUP;
+
+ /* Store setting */
+ if ( ( rc = phantom_clp_store ( phantom, phantom->port,
+ clp_setting, data, len ) ) != 0 ) {
+ DBGC ( phantom, "Phantom %p could not store setting \"%s\": "
+ "%s\n", phantom, setting->name, strerror ( rc ) );
+ return rc;
+ }
+
+ return 0;
+}
+
+/**
+ * Fetch Phantom CLP setting
+ *
+ * @v settings Settings block
+ * @v setting Setting to fetch
+ * @v data Buffer to fill with setting data
+ * @v len Length of buffer
+ * @ret len Length of setting data, or negative error
+ */
+static int phantom_fetch_setting ( struct settings *settings,
+ struct setting *setting,
+ void *data, size_t len ) {
+ struct phantom_nic *phantom =
+ container_of ( settings, struct phantom_nic, settings );
+ unsigned int clp_setting;
+ int read_len;
+ int rc;
+
+ /* Find Phantom setting equivalent to gPXE setting */
+ clp_setting = phantom_clp_setting ( phantom, setting );
+ if ( ! clp_setting )
+ return -ENOTSUP;
+
+ /* Fetch setting */
+ if ( ( read_len = phantom_clp_fetch ( phantom, phantom->port,
+ clp_setting, data, len ) ) < 0 ){
+ rc = read_len;
+ DBGC ( phantom, "Phantom %p could not fetch setting \"%s\": "
+ "%s\n", phantom, setting->name, strerror ( rc ) );
+ return rc;
+ }
+
+ return read_len;
+}
+
+/** Phantom CLP settings operations */
+static struct settings_operations phantom_settings_operations = {
+ .store = phantom_store_setting,
+ .fetch = phantom_fetch_setting,
+};
+
+/***************************************************************************
+ *
+ * Initialisation
+ *
+ */
+
/**
* Map Phantom CRB window
*
@@ -1556,8 +1742,15 @@ static int phantom_map_crb ( struct phantom_nic *phantom,
bar0_start = pci_bar_start ( pci, PCI_BASE_ADDRESS_0 );
bar0_size = pci_bar_size ( pci, PCI_BASE_ADDRESS_0 );
- DBGC ( phantom, "Phantom %p BAR0 is %08lx+%lx\n",
- phantom, bar0_start, bar0_size );
+ DBGC ( phantom, "Phantom %p is PCI %02x:%02x.%x with BAR0 at "
+ "%08lx+%lx\n", phantom, pci->bus, PCI_SLOT ( pci->devfn ),
+ PCI_FUNC ( pci->devfn ), bar0_start, bar0_size );
+
+ if ( ! bar0_start ) {
+ DBGC ( phantom, "Phantom %p BAR not assigned; ignoring\n",
+ phantom );
+ return -EINVAL;
+ }
switch ( bar0_size ) {
case ( 128 * 1024 * 1024 ) :
@@ -1592,71 +1785,23 @@ static int phantom_map_crb ( struct phantom_nic *phantom,
}
/**
- * Read Phantom flash contents
+ * Unhalt all PEGs
*
* @v phantom Phantom NIC
- * @ret rc Return status code
*/
-static int phantom_read_flash ( struct phantom_nic *phantom ) {
- struct unm_board_info board_info;
- int rc;
-
- /* Initialise flash access */
- phantom->spi_bus.rw = phantom_spi_rw;
- phantom->flash.bus = &phantom->spi_bus;
- init_m25p32 ( &phantom->flash );
- /* Phantom doesn't support greater than 4-byte block sizes */
- phantom->flash.nvs.block_size = UNM_SPI_BLKSIZE;
-
- /* Read and verify board information */
- if ( ( rc = nvs_read ( &phantom->flash.nvs, UNM_BRDCFG_START,
- &board_info, sizeof ( board_info ) ) ) != 0 ) {
- DBGC ( phantom, "Phantom %p could not read board info: %s\n",
- phantom, strerror ( rc ) );
- return rc;
- }
- if ( board_info.magic != UNM_BDINFO_MAGIC ) {
- DBGC ( phantom, "Phantom %p has bad board info magic %lx\n",
- phantom, board_info.magic );
- DBGC_HD ( phantom, &board_info, sizeof ( board_info ) );
- return -EINVAL;
- }
- if ( board_info.header_version != UNM_BDINFO_VERSION ) {
- DBGC ( phantom, "Phantom %p has bad board info version %lx\n",
- phantom, board_info.header_version );
- DBGC_HD ( phantom, &board_info, sizeof ( board_info ) );
- return -EINVAL;
- }
-
- /* Identify board type and number of ports */
- switch ( board_info.board_type ) {
- case UNM_BRDTYPE_P3_4_GB:
- case UNM_BRDTYPE_P3_4_GB_MM:
- phantom->num_ports = 4;
- break;
- case UNM_BRDTYPE_P3_HMEZ:
- case UNM_BRDTYPE_P3_IMEZ:
- case UNM_BRDTYPE_P3_10G_CX4:
- case UNM_BRDTYPE_P3_10G_CX4_LP:
- case UNM_BRDTYPE_P3_10G_SFP_PLUS:
- case UNM_BRDTYPE_P3_XG_LOM:
- phantom->num_ports = 2;
- break;
- case UNM_BRDTYPE_P3_10000_BASE_T:
- case UNM_BRDTYPE_P3_10G_XFP:
- phantom->num_ports = 1;
- break;
- default:
- DBGC ( phantom, "Phantom %p unrecognised board type %#lx; "
- "assuming single-port\n",
- phantom, board_info.board_type );
- phantom->num_ports = 1;
- break;
- }
- DBGC ( phantom, "Phantom %p board type is %#lx (%d ports)\n",
- phantom, board_info.board_type, phantom->num_ports );
-
- return 0;
+static void phantom_unhalt_pegs ( struct phantom_nic *phantom ) {
+ uint32_t halt_status;
+
+ halt_status = phantom_readl ( phantom, UNM_PEG_0_HALT_STATUS );
+ phantom_writel ( phantom, halt_status, UNM_PEG_0_HALT_STATUS );
+ halt_status = phantom_readl ( phantom, UNM_PEG_1_HALT_STATUS );
+ phantom_writel ( phantom, halt_status, UNM_PEG_1_HALT_STATUS );
+ halt_status = phantom_readl ( phantom, UNM_PEG_2_HALT_STATUS );
+ phantom_writel ( phantom, halt_status, UNM_PEG_2_HALT_STATUS );
+ halt_status = phantom_readl ( phantom, UNM_PEG_3_HALT_STATUS );
+ phantom_writel ( phantom, halt_status, UNM_PEG_3_HALT_STATUS );
+ halt_status = phantom_readl ( phantom, UNM_PEG_4_HALT_STATUS );
+ phantom_writel ( phantom, halt_status, UNM_PEG_4_HALT_STATUS );
}
/**
@@ -1668,7 +1813,6 @@ static int phantom_read_flash ( struct phantom_nic *phantom ) {
static int phantom_init_cmdpeg ( struct phantom_nic *phantom ) {
uint32_t cold_boot;
uint32_t sw_reset;
- physaddr_t dummy_dma_phys;
unsigned int retries;
uint32_t cmdpeg_state;
uint32_t last_cmdpeg_state = 0;
@@ -1681,6 +1825,11 @@ static int phantom_init_cmdpeg ( struct phantom_nic *phantom ) {
if ( cmdpeg_state == UNM_NIC_REG_CMDPEG_STATE_INITIALIZE_ACK ) {
DBGC ( phantom, "Phantom %p command PEG already initialized\n",
phantom );
+ /* Unhalt the PEGs. Previous firmware (e.g. BOFM) may
+ * have halted the PEGs to prevent internal bus
+ * collisions when the BIOS re-reads the expansion ROM.
+ */
+ phantom_unhalt_pegs ( phantom );
return 0;
}
@@ -1707,10 +1856,7 @@ static int phantom_init_cmdpeg ( struct phantom_nic *phantom ) {
UNM_CAM_RAM_WOL_PORT_MODE );
/* Pass dummy DMA area to card */
- dummy_dma_phys = virt_to_bus ( phantom->dma_buf->dummy_dma );
- DBGC ( phantom, "Phantom %p dummy DMA at %08lx\n",
- phantom, dummy_dma_phys );
- phantom_write_hilo ( phantom, dummy_dma_phys,
+ phantom_write_hilo ( phantom, 0,
UNM_NIC_REG_DUMMY_BUF_ADDR_LO,
UNM_NIC_REG_DUMMY_BUF_ADDR_HI );
phantom_writel ( phantom, UNM_NIC_REG_DUMMY_BUF_INIT,
@@ -1750,12 +1896,11 @@ static int phantom_init_cmdpeg ( struct phantom_nic *phantom ) {
/**
* Read Phantom MAC address
*
- * @v phanton_port Phantom NIC port
+ * @v phanton_port Phantom NIC
* @v ll_addr Buffer to fill with MAC address
*/
-static void phantom_get_macaddr ( struct phantom_nic_port *phantom_port,
+static void phantom_get_macaddr ( struct phantom_nic *phantom,
uint8_t *ll_addr ) {
- struct phantom_nic *phantom = phantom_port->phantom;
union {
uint8_t mac_addr[2][ETH_ALEN];
uint32_t dwords[3];
@@ -1765,7 +1910,7 @@ static void phantom_get_macaddr ( struct phantom_nic_port *phantom_port,
/* Read the three dwords that include this MAC address and one other */
offset = ( UNM_CAM_RAM_MAC_ADDRS +
- ( 12 * ( phantom_port->port / 2 ) ) );
+ ( 12 * ( phantom->port / 2 ) ) );
for ( i = 0 ; i < 3 ; i++, offset += 4 ) {
u.dwords[i] = phantom_readl ( phantom, offset );
}
@@ -1773,10 +1918,36 @@ static void phantom_get_macaddr ( struct phantom_nic_port *phantom_port,
/* Copy out the relevant MAC address */
for ( i = 0 ; i < ETH_ALEN ; i++ ) {
ll_addr[ ETH_ALEN - i - 1 ] =
- u.mac_addr[ phantom_port->port & 1 ][i];
+ u.mac_addr[ phantom->port & 1 ][i];
}
- DBGC ( phantom, "Phantom %p port %d MAC address is %s\n",
- phantom, phantom_port->port, eth_ntoa ( ll_addr ) );
+ DBGC ( phantom, "Phantom %p MAC address is %s\n",
+ phantom, eth_ntoa ( ll_addr ) );
+}
+
+/**
+ * Check Phantom is enabled for boot
+ *
+ * @v phanton_port Phantom NIC
+ * @ret rc Return status code
+ *
+ * This is something of an ugly hack to accommodate an OEM
+ * requirement. The NIC has only one expansion ROM BAR, rather than
+ * one per port. To allow individual ports to be selectively
+ * enabled/disabled for PXE boot (as required), we must therefore
+ * leave the expansion ROM always enabled, and place the per-port
+ * enable/disable logic within the gPXE driver.
+ */
+static int phantom_check_boot_enable ( struct phantom_nic *phantom ) {
+ unsigned long boot_enable;
+
+ boot_enable = phantom_readl ( phantom, UNM_CAM_RAM_BOOT_ENABLE );
+ if ( ! ( boot_enable & ( 1 << phantom->port ) ) ) {
+ DBGC ( phantom, "Phantom %p PXE boot is disabled\n",
+ phantom );
+ return -ENOTSUP;
+ }
+
+ return 0;
}
/**
@@ -1820,25 +1991,27 @@ static int phantom_init_rcvpeg ( struct phantom_nic *phantom ) {
*/
static int phantom_probe ( struct pci_device *pci,
const struct pci_device_id *id __unused ) {
- struct phantom_nic *phantom;
struct net_device *netdev;
- struct phantom_nic_port *phantom_port;
- int i;
+ struct phantom_nic *phantom;
+ struct settings *parent_settings;
int rc;
- /* Phantom NICs expose multiple PCI functions, used for
- * virtualisation. Ignore everything except function 0.
- */
- if ( PCI_FUNC ( pci->devfn ) != 0 )
- return -ENODEV;
-
/* Allocate Phantom device */
- phantom = zalloc ( sizeof ( *phantom ) );
- if ( ! phantom ) {
+ netdev = alloc_etherdev ( sizeof ( *phantom ) );
+ if ( ! netdev ) {
rc = -ENOMEM;
- goto err_alloc_phantom;
+ goto err_alloc_etherdev;
}
- pci_set_drvdata ( pci, phantom );
+ netdev_init ( netdev, &phantom_operations );
+ phantom = netdev_priv ( netdev );
+ pci_set_drvdata ( pci, netdev );
+ netdev->dev = &pci->dev;
+ memset ( phantom, 0, sizeof ( *phantom ) );
+ phantom->port = PCI_FUNC ( pci->devfn );
+ assert ( phantom->port < PHN_MAX_NUM_PORTS );
+ settings_init ( &phantom->settings,
+ &phantom_settings_operations,
+ &netdev->refcnt, "clp", PHN_CLP_TAG_MAGIC );
/* Fix up PCI device */
adjust_pci_device ( pci );
@@ -1847,87 +2020,66 @@ static int phantom_probe ( struct pci_device *pci,
if ( ( rc = phantom_map_crb ( phantom, pci ) ) != 0 )
goto err_map_crb;
- /* Read flash information */
- if ( ( rc = phantom_read_flash ( phantom ) ) != 0 )
- goto err_read_flash;
-
- /* Allocate net devices for each port */
- for ( i = 0 ; i < phantom->num_ports ; i++ ) {
- netdev = alloc_etherdev ( sizeof ( *phantom_port ) );
- if ( ! netdev ) {
- rc = -ENOMEM;
- goto err_alloc_etherdev;
- }
- phantom->netdev[i] = netdev;
- netdev_init ( netdev, &phantom_operations );
- phantom_port = netdev_priv ( netdev );
- netdev->dev = &pci->dev;
- phantom_port->phantom = phantom;
- phantom_port->port = i;
- }
-
/* BUG5945 - need to hack PCI config space on P3 B1 silicon.
* B2 will have this fixed; remove this hack when B1 is no
* longer in use.
*/
- for ( i = 0 ; i < 8 ; i++ ) {
- uint32_t temp;
- pci->devfn = PCI_DEVFN ( PCI_SLOT ( pci->devfn ), i );
- pci_read_config_dword ( pci, 0xc8, &temp );
- pci_read_config_dword ( pci, 0xc8, &temp );
- pci_write_config_dword ( pci, 0xc8, 0xf1000 );
+ if ( PCI_FUNC ( pci->devfn ) == 0 ) {
+ unsigned int i;
+ for ( i = 0 ; i < 8 ; i++ ) {
+ uint32_t temp;
+ pci->devfn = PCI_DEVFN ( PCI_SLOT ( pci->devfn ), i );
+ pci_read_config_dword ( pci, 0xc8, &temp );
+ pci_read_config_dword ( pci, 0xc8, &temp );
+ pci_write_config_dword ( pci, 0xc8, 0xf1000 );
+ }
+ pci->devfn = PCI_DEVFN ( PCI_SLOT ( pci->devfn ), 0 );
}
- pci->devfn = PCI_DEVFN ( PCI_SLOT ( pci->devfn ), 0 );
- /* Allocate dummy DMA buffer and perform initial hardware handshake */
- phantom->dma_buf = malloc_dma ( sizeof ( *(phantom->dma_buf) ),
- UNM_DMA_BUFFER_ALIGN );
- if ( ! phantom->dma_buf )
- goto err_dma_buf;
+ /* Initialise the command PEG */
if ( ( rc = phantom_init_cmdpeg ( phantom ) ) != 0 )
goto err_init_cmdpeg;
- /* Initialise the receive firmware */
+ /* Initialise the receive PEG */
if ( ( rc = phantom_init_rcvpeg ( phantom ) ) != 0 )
goto err_init_rcvpeg;
/* Read MAC addresses */
- for ( i = 0 ; i < phantom->num_ports ; i++ ) {
- phantom_port = netdev_priv ( phantom->netdev[i] );
- phantom_get_macaddr ( phantom_port,
- phantom->netdev[i]->ll_addr );
- }
+ phantom_get_macaddr ( phantom, netdev->ll_addr );
+
+ /* Skip if boot disabled on NIC */
+ if ( ( rc = phantom_check_boot_enable ( phantom ) ) != 0 )
+ goto err_check_boot_enable;
/* Register network devices */
- for ( i = 0 ; i < phantom->num_ports ; i++ ) {
- if ( ( rc = register_netdev ( phantom->netdev[i] ) ) != 0 ) {
- DBGC ( phantom, "Phantom %p could not register port "
- "%d: %s\n", phantom, i, strerror ( rc ) );
- goto err_register_netdev;
- }
+ if ( ( rc = register_netdev ( netdev ) ) != 0 ) {
+ DBGC ( phantom, "Phantom %p could not register net device: "
+ "%s\n", phantom, strerror ( rc ) );
+ goto err_register_netdev;
+ }
+
+ /* Register settings blocks */
+ parent_settings = netdev_settings ( netdev );
+ if ( ( rc = register_settings ( &phantom->settings,
+ parent_settings ) ) != 0 ) {
+ DBGC ( phantom, "Phantom %p could not register settings: "
+ "%s\n", phantom, strerror ( rc ) );
+ goto err_register_settings;
}
return 0;
- i = ( phantom->num_ports - 1 );
+ unregister_settings ( &phantom->settings );
+ err_register_settings:
+ unregister_netdev ( netdev );
err_register_netdev:
- for ( ; i >= 0 ; i-- )
- unregister_netdev ( phantom->netdev[i] );
+ err_check_boot_enable:
err_init_rcvpeg:
err_init_cmdpeg:
- free_dma ( phantom->dma_buf, sizeof ( *(phantom->dma_buf) ) );
- phantom->dma_buf = NULL;
- err_dma_buf:
- i = ( phantom->num_ports - 1 );
- err_alloc_etherdev:
- for ( ; i >= 0 ; i-- ) {
- netdev_nullify ( phantom->netdev[i] );
- netdev_put ( phantom->netdev[i] );
- }
- err_read_flash:
err_map_crb:
- free ( phantom );
- err_alloc_phantom:
+ netdev_nullify ( netdev );
+ netdev_put ( netdev );
+ err_alloc_etherdev:
return rc;
}
@@ -1937,18 +2089,13 @@ static int phantom_probe ( struct pci_device *pci,
* @v pci PCI device
*/
static void phantom_remove ( struct pci_device *pci ) {
- struct phantom_nic *phantom = pci_get_drvdata ( pci );
- int i;
+ struct net_device *netdev = pci_get_drvdata ( pci );
+ struct phantom_nic *phantom = netdev_priv ( netdev );
- for ( i = ( phantom->num_ports - 1 ) ; i >= 0 ; i-- )
- unregister_netdev ( phantom->netdev[i] );
- free_dma ( phantom->dma_buf, sizeof ( *(phantom->dma_buf) ) );
- phantom->dma_buf = NULL;
- for ( i = ( phantom->num_ports - 1 ) ; i >= 0 ; i-- ) {
- netdev_nullify ( phantom->netdev[i] );
- netdev_put ( phantom->netdev[i] );
- }
- free ( phantom );
+ unregister_settings ( &phantom->settings );
+ unregister_netdev ( netdev );
+ netdev_nullify ( netdev );
+ netdev_put ( netdev );
}
/** Phantom PCI IDs */
diff --git a/gpxe/src/drivers/net/phantom/phantom.h b/gpxe/src/drivers/net/phantom/phantom.h
index 110c1226..974eecae 100644
--- a/gpxe/src/drivers/net/phantom/phantom.h
+++ b/gpxe/src/drivers/net/phantom/phantom.h
@@ -45,18 +45,12 @@ typedef uint32_t nx_rcode_t;
#define NXHAL_VERSION 1
#include "nxhal_nic_interface.h"
-/** SPI controller maximum block size */
-#define UNM_SPI_BLKSIZE 4
-
/** DMA buffer alignment */
#define UNM_DMA_BUFFER_ALIGN 16
/** Mark structure as DMA-aligned */
#define __unm_dma_aligned __attribute__ (( aligned ( UNM_DMA_BUFFER_ALIGN ) ))
-/** Dummy DMA buffer size */
-#define UNM_DUMMY_DMA_SIZE 1024
-
/******************************************************************************
*
* Register definitions
@@ -76,14 +70,19 @@ typedef uint32_t nx_rcode_t;
* address by the phantom_crb_access_xxx() methods.
*/
enum unm_reg_blocks {
- UNM_CRB_BLK_PCIE,
- UNM_CRB_BLK_CAM,
- UNM_CRB_BLK_ROMUSB,
- UNM_CRB_BLK_TEST,
+ UNM_CRB_BLK_PCIE = 0x01,
+ UNM_CRB_BLK_CAM = 0x22,
+ UNM_CRB_BLK_ROMUSB = 0x33,
+ UNM_CRB_BLK_TEST = 0x02,
+ UNM_CRB_BLK_PEG_0 = 0x11,
+ UNM_CRB_BLK_PEG_1 = 0x12,
+ UNM_CRB_BLK_PEG_2 = 0x13,
+ UNM_CRB_BLK_PEG_3 = 0x14,
+ UNM_CRB_BLK_PEG_4 = 0x0f,
};
-#define UNM_CRB_BASE(blk) ( (blk) << 24 )
-#define UNM_CRB_BLK(reg) ( (reg) >> 24 )
-#define UNM_CRB_OFFSET(reg) ( (reg) & 0x00ffffff )
+#define UNM_CRB_BASE(blk) ( (blk) << 20 )
+#define UNM_CRB_BLK(reg) ( (reg) >> 20 )
+#define UNM_CRB_OFFSET(reg) ( (reg) & 0x000fffff )
#define UNM_CRB_PCIE UNM_CRB_BASE ( UNM_CRB_BLK_PCIE )
#define UNM_PCIE_SEM2_LOCK ( UNM_CRB_PCIE + 0x1c010 )
@@ -101,6 +100,16 @@ enum unm_reg_blocks {
#define UNM_CAM_RAM_DMESG_SIG(n) ( UNM_CAM_RAM + 0x0003c + (n) * 0x10 )
#define UNM_CAM_RAM_DMESG_SIG_MAGIC 0xcafebabeUL
#define UNM_CAM_RAM_NUM_DMESG_BUFFERS 5
+#define UNM_CAM_RAM_CLP_COMMAND ( UNM_CAM_RAM + 0x000c0 )
+#define UNM_CAM_RAM_CLP_COMMAND_LAST 0x00000080UL
+#define UNM_CAM_RAM_CLP_DATA_LO ( UNM_CAM_RAM + 0x000c4 )
+#define UNM_CAM_RAM_CLP_DATA_HI ( UNM_CAM_RAM + 0x000c8 )
+#define UNM_CAM_RAM_CLP_STATUS ( UNM_CAM_RAM + 0x000cc )
+#define UNM_CAM_RAM_CLP_STATUS_START 0x00000001UL
+#define UNM_CAM_RAM_CLP_STATUS_DONE 0x00000002UL
+#define UNM_CAM_RAM_CLP_STATUS_ERROR 0x0000ff00UL
+#define UNM_CAM_RAM_CLP_STATUS_UNINITIALISED 0xffffffffUL
+#define UNM_CAM_RAM_BOOT_ENABLE ( UNM_CAM_RAM + 0x000fc )
#define UNM_CAM_RAM_WOL_PORT_MODE ( UNM_CAM_RAM + 0x00198 )
#define UNM_CAM_RAM_MAC_ADDRS ( UNM_CAM_RAM + 0x001c0 )
#define UNM_CAM_RAM_COLD_BOOT ( UNM_CAM_RAM + 0x001fc )
@@ -160,114 +169,24 @@ enum unm_reg_blocks {
#define UNM_TEST_RDDATA_LO ( UNM_CRB_TEST + 0x000a8 )
#define UNM_TEST_RDDATA_HI ( UNM_CRB_TEST + 0x000ac )
-/******************************************************************************
- *
- * Flash layout
- *
- */
-
-/* Board configuration */
-
-#define UNM_BRDCFG_START 0x4000
-
-struct unm_board_info {
- uint32_t header_version;
- uint32_t board_mfg;
- uint32_t board_type;
- uint32_t board_num;
- uint32_t chip_id;
- uint32_t chip_minor;
- uint32_t chip_major;
- uint32_t chip_pkg;
- uint32_t chip_lot;
- uint32_t port_mask;
- uint32_t peg_mask;
- uint32_t icache_ok;
- uint32_t dcache_ok;
- uint32_t casper_ok;
- uint32_t mac_addr_lo_0;
- uint32_t mac_addr_lo_1;
- uint32_t mac_addr_lo_2;
- uint32_t mac_addr_lo_3;
- uint32_t mn_sync_mode;
- uint32_t mn_sync_shift_cclk;
- uint32_t mn_sync_shift_mclk;
- uint32_t mn_wb_en;
- uint32_t mn_crystal_freq;
- uint32_t mn_speed;
- uint32_t mn_org;
- uint32_t mn_depth;
- uint32_t mn_ranks_0;
- uint32_t mn_ranks_1;
- uint32_t mn_rd_latency_0;
- uint32_t mn_rd_latency_1;
- uint32_t mn_rd_latency_2;
- uint32_t mn_rd_latency_3;
- uint32_t mn_rd_latency_4;
- uint32_t mn_rd_latency_5;
- uint32_t mn_rd_latency_6;
- uint32_t mn_rd_latency_7;
- uint32_t mn_rd_latency_8;
- uint32_t mn_dll_val[18];
- uint32_t mn_mode_reg;
- uint32_t mn_ext_mode_reg;
- uint32_t mn_timing_0;
- uint32_t mn_timing_1;
- uint32_t mn_timing_2;
- uint32_t sn_sync_mode;
- uint32_t sn_pt_mode;
- uint32_t sn_ecc_en;
- uint32_t sn_wb_en;
- uint32_t sn_crystal_freq;
- uint32_t sn_speed;
- uint32_t sn_org;
- uint32_t sn_depth;
- uint32_t sn_dll_tap;
- uint32_t sn_rd_latency;
- uint32_t mac_addr_hi_0;
- uint32_t mac_addr_hi_1;
- uint32_t mac_addr_hi_2;
- uint32_t mac_addr_hi_3;
- uint32_t magic;
- uint32_t mn_rdimm;
- uint32_t mn_dll_override;
-};
-
-#define UNM_BDINFO_VERSION 1
-#define UNM_BRDTYPE_P3_HMEZ 0x0022
-#define UNM_BRDTYPE_P3_10G_CX4_LP 0x0023
-#define UNM_BRDTYPE_P3_4_GB 0x0024
-#define UNM_BRDTYPE_P3_IMEZ 0x0025
-#define UNM_BRDTYPE_P3_10G_SFP_PLUS 0x0026
-#define UNM_BRDTYPE_P3_10000_BASE_T 0x0027
-#define UNM_BRDTYPE_P3_XG_LOM 0x0028
-#define UNM_BRDTYPE_P3_4_GB_MM 0x0029
-#define UNM_BRDTYPE_P3_10G_CX4 0x0031
-#define UNM_BRDTYPE_P3_10G_XFP 0x0032
-#define UNM_BDINFO_MAGIC 0x12345678
+#define UNM_CRB_PEG_0 UNM_CRB_BASE ( UNM_CRB_BLK_PEG_0 )
+#define UNM_PEG_0_HALT_STATUS ( UNM_CRB_PEG_0 + 0x00030 )
+#define UNM_PEG_0_HALT ( UNM_CRB_PEG_0 + 0x0003c )
-/* User defined region */
+#define UNM_CRB_PEG_1 UNM_CRB_BASE ( UNM_CRB_BLK_PEG_1 )
+#define UNM_PEG_1_HALT_STATUS ( UNM_CRB_PEG_1 + 0x00030 )
+#define UNM_PEG_1_HALT ( UNM_CRB_PEG_1 + 0x0003c )
-#define UNM_USER_START 0x3e8000
+#define UNM_CRB_PEG_2 UNM_CRB_BASE ( UNM_CRB_BLK_PEG_2 )
+#define UNM_PEG_2_HALT_STATUS ( UNM_CRB_PEG_2 + 0x00030 )
+#define UNM_PEG_2_HALT ( UNM_CRB_PEG_2 + 0x0003c )
-#define UNM_FLASH_NUM_PORTS 4
-#define UNM_FLASH_NUM_MAC_PER_PORT 32
+#define UNM_CRB_PEG_3 UNM_CRB_BASE ( UNM_CRB_BLK_PEG_3 )
+#define UNM_PEG_3_HALT_STATUS ( UNM_CRB_PEG_3 + 0x00030 )
+#define UNM_PEG_3_HALT ( UNM_CRB_PEG_3 + 0x0003c )
-struct unm_user_info {
- uint8_t flash_md5[16 * 64];
- uint32_t bootld_version;
- uint32_t bootld_size;
- uint32_t image_version;
- uint32_t image_size;
- uint32_t primary_status;
- uint32_t secondary_present;
- /* MAC address , 4 ports, 32 address per port */
- uint64_t mac_addr[UNM_FLASH_NUM_PORTS * UNM_FLASH_NUM_MAC_PER_PORT];
- uint32_t sub_sys_id;
- uint8_t serial_num[32];
- uint32_t bios_version;
- uint32_t pxe_enable;
- uint32_t vlan_tag[UNM_FLASH_NUM_PORTS];
-};
+#define UNM_CRB_PEG_4 UNM_CRB_BASE ( UNM_CRB_BLK_PEG_4 )
+#define UNM_PEG_4_HALT_STATUS ( UNM_CRB_PEG_4 + 0x00030 )
+#define UNM_PEG_4_HALT ( UNM_CRB_PEG_4 + 0x0003c )
#endif /* _PHANTOM_H */
diff --git a/gpxe/src/drivers/net/pnic.c b/gpxe/src/drivers/net/pnic.c
index c7f08670..3a4af967 100644
--- a/gpxe/src/drivers/net/pnic.c
+++ b/gpxe/src/drivers/net/pnic.c
@@ -14,7 +14,7 @@ Bochs Pseudo NIC driver for Etherboot
#include <stdint.h>
#include <stdio.h>
-#include <io.h>
+#include <gpxe/io.h>
#include <errno.h>
#include <gpxe/pci.h>
#include <gpxe/if_ether.h>
diff --git a/gpxe/src/drivers/net/r8169.c b/gpxe/src/drivers/net/r8169.c
index 885f054a..0554058e 100644
--- a/gpxe/src/drivers/net/r8169.c
+++ b/gpxe/src/drivers/net/r8169.c
@@ -1,1159 +1,434 @@
-/**************************************************************************
-* r8169.c: Etherboot device driver for the RealTek RTL-8169 Gigabit
-* Written 2003 by Timothy Legge <tlegge@rogers.com>
-*
-* This program is free software; you can redistribute it and/or modify
-* it under the terms of the GNU General Public License as published by
-* the Free Software Foundation; either version 2 of the License, or
-* (at your option) any later version.
-*
-* This program is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-* GNU General Public License for more details.
-*
-* You should have received a copy of the GNU General Public License
-* along with this program; if not, write to the Free Software
-* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*
-* Portions of this code based on:
-* r8169.c: A RealTek RTL-8169 Gigabit Ethernet driver
-* for Linux kernel 2.4.x.
-*
-* Written 2002 ShuChen <shuchen@realtek.com.tw>
-* See Linux Driver for full information
-*
-* Linux Driver Versions:
-* 1.27a, 10.02.2002
-* RTL8169_VERSION "2.2" <2004/08/09>
-*
-* Thanks to:
-* Jean Chen of RealTek Semiconductor Corp. for
-* providing the evaluation NIC used to develop
-* this driver. RealTek's support for Etherboot
-* is appreciated.
-*
-* REVISION HISTORY:
-* ================
-*
-* v1.0 11-26-2003 timlegge Initial port of Linux driver
-* v1.5 01-17-2004 timlegge Initial driver output cleanup
-* v1.6 03-27-2004 timlegge Additional Cleanup
-* v1.7 11-22-2005 timlegge Update to RealTek Driver Version 2.2
-*
-* 03-19-2008 Hilko Bengen Cleanups and fixes for newer cards
-* (successfully tested with 8110SC-d onboard NIC)
-*
-* Indent Options: indent -kr -i8
-***************************************************************************/
-
-#include "etherboot.h"
-#include "nic.h"
-#include <gpxe/pci.h>
+/*
+ * Copyright (c) 2008 Marty Connor <mdc@etherboot.org>
+ * Copyright (c) 2008 Entity Cyber, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * This driver is based on rtl8169 data sheets and work by:
+ *
+ * Copyright (c) 2002 ShuChen <shuchen@realtek.com.tw>
+ * Copyright (c) 2003 - 2007 Francois Romieu <romieu@fr.zoreil.com>
+ * Copyright (c) a lot of people too. Please respect their work.
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <assert.h>
+#include <byteswap.h>
+#include <errno.h>
#include <gpxe/ethernet.h>
+#include <gpxe/if_ether.h>
+#include <gpxe/io.h>
+#include <gpxe/iobuf.h>
#include <gpxe/malloc.h>
+#include <gpxe/netdevice.h>
+#include <gpxe/pci.h>
+#include <gpxe/timer.h>
-#define drv_version "v1.7+"
-#define drv_date "03-19-2008"
-
-#define HZ 1000
-
-static u32 ioaddr;
-
-/* Condensed operations for readability. */
-#define virt_to_le32desc(addr) cpu_to_le32(virt_to_bus(addr))
-#define le32desc_to_virt(addr) bus_to_virt(le32_to_cpu(addr))
-
-#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
-
-#undef RTL8169_DEBUG
-#undef RTL8169_JUMBO_FRAME_SUPPORT
-#undef RTL8169_HW_FLOW_CONTROL_SUPPORT
-
-
-#undef RTL8169_IOCTL_SUPPORT
-#undef RTL8169_DYNAMIC_CONTROL
-#define RTL8169_USE_IO
-
-#if 0
-/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
-static int max_interrupt_work = 20;
-#endif
-
-#if 0
-/* Maximum number of multicast addresses to filter (vs. Rx-all-multicast).
- The RTL chips use a 64 element hash table based on the Ethernet CRC. */
-static int multicast_filter_limit = 32;
-#endif
-
-/* MAC address length*/
-#define MAC_ADDR_LEN 6
-
-/* max supported gigabit ethernet frame size -- must be at least (dev->mtu+14+4).*/
-#define MAX_ETH_FRAME_SIZE 1536
-
-#define TX_FIFO_THRESH 256 /* In bytes */
-
-#define RX_FIFO_THRESH 7 /* 7 means NO threshold, Rx buffer level before first PCI xfer. */
-#define RX_DMA_BURST 7 /* Maximum PCI burst, '6' is 1024 */
-#define TX_DMA_BURST 7 /* Maximum PCI burst, '6' is 1024 */
-#define ETTh 0x3F /* 0x3F means NO threshold */
-
-#define EarlyTxThld 0x3F /* 0x3F means NO early transmit */
-#define RxPacketMaxSize 0x0800 /* Maximum size supported is 16K-1 */
-#define InterFrameGap 0x03 /* 3 means InterFrameGap = the shortest one */
-
-#define NUM_TX_DESC 1 /* Number of Tx descriptor registers */
-#define NUM_RX_DESC 4 /* Number of Rx descriptor registers */
-#define RX_BUF_SIZE 1536 /* Rx Buffer size */
-
-#define RTL_MIN_IO_SIZE 0x80
-#define TX_TIMEOUT (6*HZ)
-
-#define RTL8169_TIMER_EXPIRE_TIME 100 //100
-
-#define ETH_HDR_LEN 14
-#define DEFAULT_MTU 1500
-#define DEFAULT_RX_BUF_LEN 1536
-
-
-#ifdef RTL8169_JUMBO_FRAME_SUPPORT
-#define MAX_JUMBO_FRAME_MTU ( 10000 )
-#define MAX_RX_SKBDATA_SIZE ( MAX_JUMBO_FRAME_MTU + ETH_HDR_LEN )
-#else
-#define MAX_RX_SKBDATA_SIZE 1600
-#endif //end #ifdef RTL8169_JUMBO_FRAME_SUPPORT
-
-#ifdef RTL8169_USE_IO
-#define RTL_W8(reg, val8) outb ((val8), ioaddr + (reg))
-#define RTL_W16(reg, val16) outw ((val16), ioaddr + (reg))
-#define RTL_W32(reg, val32) outl ((val32), ioaddr + (reg))
-#define RTL_R8(reg) inb (ioaddr + (reg))
-#define RTL_R16(reg) inw (ioaddr + (reg))
-#define RTL_R32(reg) ((unsigned long) inl (ioaddr + (reg)))
-#else
-/* write/read MMIO register */
-#define RTL_W8(reg, val8) writeb ((val8), ioaddr + (reg))
-#define RTL_W16(reg, val16) writew ((val16), ioaddr + (reg))
-#define RTL_W32(reg, val32) writel ((val32), ioaddr + (reg))
-#define RTL_R8(reg) readb (ioaddr + (reg))
-#define RTL_R16(reg) readw (ioaddr + (reg))
-#define RTL_R32(reg) ((unsigned long) readl (ioaddr + (reg)))
-#endif
-
-enum mac_version {
- RTL_GIGA_MAC_VER_01 = 0x01, // 8169
- RTL_GIGA_MAC_VER_02 = 0x02, // 8169S
- RTL_GIGA_MAC_VER_03 = 0x03, // 8110S
- RTL_GIGA_MAC_VER_04 = 0x04, // 8169SB
- RTL_GIGA_MAC_VER_05 = 0x05, // 8110SCd
- RTL_GIGA_MAC_VER_06 = 0x06, // 8110SCe
- RTL_GIGA_MAC_VER_11 = 0x0b, // 8168Bb
- RTL_GIGA_MAC_VER_12 = 0x0c, // 8168Be
- RTL_GIGA_MAC_VER_13 = 0x0d, // 8101Eb
- RTL_GIGA_MAC_VER_14 = 0x0e, // 8101 ?
- RTL_GIGA_MAC_VER_15 = 0x0f, // 8101 ?
- RTL_GIGA_MAC_VER_16 = 0x11, // 8101Ec
- RTL_GIGA_MAC_VER_17 = 0x10, // 8168Bf
- RTL_GIGA_MAC_VER_18 = 0x12, // 8168CP
- RTL_GIGA_MAC_VER_19 = 0x13, // 8168C
- RTL_GIGA_MAC_VER_20 = 0x14 // 8168C
-};
-
-enum cfg_version {
- RTL_CFG_0 = 0x00,
- RTL_CFG_1,
- RTL_CFG_2
-};
-
-static struct {
- const char *name;
- u8 mac_version; /* depend on RTL8169 docs */
- u32 RxConfigMask; /* should clear the bits supported by this chip */
-} rtl_chip_info[] = {
- {"RTL8169", RTL_GIGA_MAC_VER_01, 0xff7e1880}, // 8169
- {"RTL8169s", RTL_GIGA_MAC_VER_02, 0xff7e1880}, // 8169S
- {"RTL8110s", RTL_GIGA_MAC_VER_03, 0xff7e1880}, // 8110S
- {"RTL8169sb/8110sb", RTL_GIGA_MAC_VER_04, 0xff7e1880}, // 8169SB
- {"RTL8169sc/8110sc-d",RTL_GIGA_MAC_VER_05, 0xff7e1880}, // 8110SCd
- {"RTL8169sc/8110sc-e",RTL_GIGA_MAC_VER_06, 0xff7e1880}, // 8110SCe
- {"RTL8168b/8111b", RTL_GIGA_MAC_VER_11, 0xff7e1880}, // PCI-E
- {"RTL8168b/8111b", RTL_GIGA_MAC_VER_12, 0xff7e1880}, // PCI-E
- {"RTL8101e", RTL_GIGA_MAC_VER_13, 0xff7e1880}, // PCI-E 8139
- {"RTL8100e", RTL_GIGA_MAC_VER_14, 0xff7e1880}, // PCI-E 8139
- {"RTL8100e", RTL_GIGA_MAC_VER_15, 0xff7e1880}, // PCI-E 8139
- {"RTL8168b/8111b", RTL_GIGA_MAC_VER_17, 0xff7e1880}, // PCI-E
- {"RTL8101e", RTL_GIGA_MAC_VER_16, 0xff7e1880}, // PCI-E
- {"RTL8168cp/8111cp", RTL_GIGA_MAC_VER_18, 0xff7e1880}, // PCI-E
- {"RTL8168c/8111c", RTL_GIGA_MAC_VER_19, 0xff7e1880}, // PCI-E
- {"RTL8168c/8111c", RTL_GIGA_MAC_VER_20, 0xff7e1880}, // PCI-E
-};
-
-enum RTL8169_registers {
- MAC0 = 0x0, /* Ethernet hardware address. */
- MAR0 = 0x8, /* Multicast filter. */
- TxDescAddrLow = 0x20,
- TxDescAddrHigh = 0x24,
- TxHDescStartAddr = 0x28,
- FLASH = 0x30,
- ERSR = 0x36,
- ChipCmd = 0x37,
- TxPoll = 0x38,
- IntrMask = 0x3C,
- IntrStatus = 0x3E,
- TxConfig = 0x40,
- RxConfig = 0x44,
- RxMissed = 0x4C,
- Cfg9346 = 0x50,
- Config0 = 0x51,
- Config1 = 0x52,
- Config2 = 0x53,
- Config3 = 0x54,
- Config4 = 0x55,
- Config5 = 0x56,
- MultiIntr = 0x5C,
- PHYAR = 0x60,
- TBICSR = 0x64,
- TBI_ANAR = 0x68,
- TBI_LPAR = 0x6A,
- PHYstatus = 0x6C,
- RxMaxSize = 0xda,
- CPlusCmd = 0xe0,
- IntrMitigate = 0xe2,
- RxDescAddrLow = 0xe4,
- RxDescAddrHigh = 0xe8,
- ETThReg = 0xEC,
- FuncEvent = 0xF0,
- FuncEventMask = 0xF4,
- FuncPresetState = 0xF8,
- FuncForceEvent = 0xFC,
-};
-
-enum RTL8169_register_content {
- /*InterruptStatusBits */
- SYSErr = 0x8000,
- PCSTimeout = 0x4000,
- SWInt = 0x0100,
- TxDescUnavail = 0x80,
- RxFIFOOver = 0x40,
- LinkChg = 0x20,
- RxOverflow = 0x10,
- TxErr = 0x08,
- TxOK = 0x04,
- RxErr = 0x02,
- RxOK = 0x01,
-
- /*RxStatusDesc */
- RxRES = 0x00200000,
- RxCRC = 0x00080000,
- RxRUNT = 0x00100000,
- RxRWT = 0x00400000,
-
- /*ChipCmdBits */
- CmdReset = 0x10,
- CmdRxEnb = 0x08,
- CmdTxEnb = 0x04,
- RxBufEmpty = 0x01,
-
- /*Cfg9346Bits */
- Cfg9346_Lock = 0x00,
- Cfg9346_Unlock = 0xC0,
-
- /*rx_mode_bits */
- AcceptErr = 0x20,
- AcceptRunt = 0x10,
- AcceptBroadcast = 0x08,
- AcceptMulticast = 0x04,
- AcceptMyPhys = 0x02,
- AcceptAllPhys = 0x01,
-
- /*RxConfigBits */
- RxCfgFIFOShift = 13,
- RxCfgDMAShift = 8,
-
- /*TxConfigBits */
- TxInterFrameGapShift = 24,
- TxDMAShift = 8, /* DMA burst value (0-7) is shift this many bits */
-
- /*rtl8169_PHYstatus */
- TBI_Enable = 0x80,
- TxFlowCtrl = 0x40,
- RxFlowCtrl = 0x20,
- _1000bpsF = 0x10,
- _100bps = 0x08,
- _10bps = 0x04,
- LinkStatus = 0x02,
- FullDup = 0x01,
-
- /*GIGABIT_PHY_registers */
- PHY_CTRL_REG = 0,
- PHY_STAT_REG = 1,
- PHY_AUTO_NEGO_REG = 4,
- PHY_1000_CTRL_REG = 9,
-
- /*GIGABIT_PHY_REG_BIT */
- PHY_Restart_Auto_Nego = 0x0200,
- PHY_Enable_Auto_Nego = 0x1000,
-
- /* PHY_STAT_REG = 1; */
- PHY_Auto_Neco_Comp = 0x0020,
-
- /* PHY_AUTO_NEGO_REG = 4; */
- PHY_Cap_10_Half = 0x0020,
- PHY_Cap_10_Full = 0x0040,
- PHY_Cap_100_Half = 0x0080,
- PHY_Cap_100_Full = 0x0100,
-
- /* PHY_1000_CTRL_REG = 9; */
- PHY_Cap_1000_Full = 0x0200,
- PHY_Cap_1000_Half = 0x0100,
-
- PHY_Cap_PAUSE = 0x0400,
- PHY_Cap_ASYM_PAUSE = 0x0800,
-
- PHY_Cap_Null = 0x0,
-
- /*_MediaType*/
- _10_Half = 0x01,
- _10_Full = 0x02,
- _100_Half = 0x04,
- _100_Full = 0x08,
- _1000_Full = 0x10,
-
- /*_TBICSRBit*/
- TBILinkOK = 0x02000000,
-};
-
-enum _DescStatusBit {
- OWNbit = 0x80000000,
- EORbit = 0x40000000,
- FSbit = 0x20000000,
- LSbit = 0x10000000,
-};
-
-struct TxDesc {
- u32 status;
- u32 vlan_tag;
- u32 buf_addr;
- u32 buf_Haddr;
-};
-
-struct RxDesc {
- u32 status;
- u32 vlan_tag;
- u32 buf_addr;
- u32 buf_Haddr;
-};
+#include "r8169.h"
-/* The descriptors for this card are required to be aligned on 256
- * byte boundaries. As the align attribute does not do more than 16
- * bytes of alignment it requires some extra steps. Add 256 to the
- * size of the array and the init_ring adjusts the alignment.
- *
- * UPDATE: This is no longer true; we can request arbitrary alignment.
- */
+/*** Low level hardware routines ***/
-/* Define the TX and RX Descriptors and Buffers */
-#define __align_256 __attribute__ (( aligned ( 256 ) ))
-struct {
- struct TxDesc tx_ring[NUM_TX_DESC] __align_256;
- unsigned char txb[NUM_TX_DESC * RX_BUF_SIZE];
- struct RxDesc rx_ring[NUM_RX_DESC] __align_256;
- unsigned char rxb[NUM_RX_DESC * RX_BUF_SIZE];
-} *r8169_bufs;
-#define tx_ring r8169_bufs->tx_ring
-#define rx_ring r8169_bufs->rx_ring
-#define txb r8169_bufs->txb
-#define rxb r8169_bufs->rxb
-
-static struct rtl8169_private {
- void *mmio_addr; /* memory map physical address */
- int chipset;
- int pcfg;
- int mac_version;
- unsigned long cur_rx; /* Index into the Rx descriptor buffer of next Rx pkt. */
- unsigned long cur_tx; /* Index into the Tx descriptor buffer of next Rx pkt. */
- struct TxDesc *TxDescArray; /* Index of 256-alignment Tx Descriptor buffer */
- struct RxDesc *RxDescArray; /* Index of 256-alignment Rx Descriptor buffer */
- unsigned char *RxBufferRing[NUM_RX_DESC]; /* Index of Rx Buffer array */
- unsigned char *Tx_skbuff[NUM_TX_DESC];
-} tpx;
-
-static const u16 rtl8169_intr_mask =
- LinkChg | RxOverflow | RxFIFOOver | TxErr | TxOK | RxErr | RxOK;
-static const unsigned int rtl8169_rx_config =
- (RX_FIFO_THRESH << RxCfgFIFOShift) | (RX_DMA_BURST << RxCfgDMAShift) |
- 0x0000000E;
-
-static void rtl8169_hw_phy_config(struct nic *nic __unused);
-//static void rtl8169_hw_phy_reset(struct net_device *dev);
-
-#define RTL8169_WRITE_GMII_REG_BIT( ioaddr, reg, bitnum, bitval )\
-{ \
- int val; \
- if( bitval == 1 ){ val = ( RTL8169_READ_GMII_REG( ioaddr, reg ) | (bitval<<bitnum) ) & 0xffff ; } \
- else{ val = ( RTL8169_READ_GMII_REG( ioaddr, reg ) & (~(0x0001<<bitnum)) ) & 0xffff ; } \
- RTL8169_WRITE_GMII_REG( ioaddr, reg, val ); \
- }
-
-//=================================================================
-// PHYAR
-// bit Symbol
-// 31 Flag
-// 30-21 reserved
-// 20-16 5-bit GMII/MII register address
-// 15-0 16-bit GMII/MII register data
-//=================================================================
-static void RTL8169_WRITE_GMII_REG(unsigned long ioaddr, int RegAddr, int value)
+static void mdio_write(void *ioaddr, int reg_addr, int value)
{
int i;
- RTL_W32(PHYAR, 0x80000000 | (RegAddr & 0xFF) << 16 | value);
- udelay(1000);
+ DBGP ( "mdio_write\n" );
- for (i = 2000; i > 0; i--) {
- // Check if the RTL8169 has completed writing to the specified MII register
- if (!(RTL_R32(PHYAR) & 0x80000000)) {
+ RTL_W32(PHYAR, 0x80000000 | (reg_addr & 0x1f) << 16 | (value & 0xffff));
+
+ for (i = 20; i > 0; i--) {
+ /*
+ * Check if the RTL8169 has completed writing to the specified
+ * MII register.
+ */
+ if (!(RTL_R32(PHYAR) & 0x80000000))
break;
- } else {
- udelay(100);
- } // end of if( ! (RTL_R32(PHYAR)&0x80000000) )
- } // end of for() loop
+ udelay(25);
+ }
}
-//=================================================================
-static int RTL8169_READ_GMII_REG(unsigned long ioaddr, int RegAddr)
+static int mdio_read(void *ioaddr, int reg_addr)
{
int i, value = -1;
- RTL_W32(PHYAR, 0x0 | (RegAddr & 0xFF) << 16);
- udelay(1000);
+ DBGP ( "mdio_read\n" );
+
+ RTL_W32(PHYAR, 0x0 | (reg_addr & 0x1f) << 16);
- for (i = 2000; i > 0; i--) {
- // Check if the RTL8169 has completed retrieving data from the specified MII register
+ for (i = 20; i > 0; i--) {
+ /*
+ * Check if the RTL8169 has completed retrieving data from
+ * the specified MII register.
+ */
if (RTL_R32(PHYAR) & 0x80000000) {
- value = (int) (RTL_R32(PHYAR) & 0xFFFF);
+ value = RTL_R32(PHYAR) & 0xffff;
break;
- } else {
- udelay(100);
- } // end of if( RTL_R32(PHYAR) & 0x80000000 )
- } // end of for() loop
+ }
+ udelay(25);
+ }
return value;
}
+static void mdio_patch(void *ioaddr, int reg_addr, int value)
+{
+ DBGP ( "mdio_patch\n" );
+
+ mdio_write(ioaddr, reg_addr, mdio_read(ioaddr, reg_addr) | value);
+}
-#if 0
-static void mdio_write(int RegAddr, int value)
+static void rtl_ephy_write(void *ioaddr, int reg_addr, int value)
{
- int i;
+ unsigned int i;
+
+ DBGP ( "rtl_ephy_write\n" );
- RTL_W32(PHYAR, 0x80000000 | (RegAddr & 0xFF) << 16 | value);
- udelay(1000);
+ RTL_W32(EPHYAR, EPHYAR_WRITE_CMD | (value & EPHYAR_DATA_MASK) |
+ (reg_addr & EPHYAR_REG_MASK) << EPHYAR_REG_SHIFT);
- for (i = 2000; i > 0; i--) {
- /* Check if the RTL8169 has completed writing to the specified MII register */
- if (!(RTL_R32(PHYAR) & 0x80000000)) {
+ for (i = 0; i < 100; i++) {
+ if (!(RTL_R32(EPHYAR) & EPHYAR_FLAG))
break;
- } else {
- udelay(100);
- }
+ udelay(10);
}
}
-static int mdio_read(int RegAddr)
+static u16 rtl_ephy_read(void *ioaddr, int reg_addr)
{
- int i, value = -1;
+ u16 value = 0xffff;
+ unsigned int i;
- RTL_W32(PHYAR, 0x0 | (RegAddr & 0xFF) << 16);
- udelay(1000);
+ DBGP ( "rtl_ephy_read\n" );
- for (i = 2000; i > 0; i--) {
- /* Check if the RTL8169 has completed retrieving data from the specified MII register */
- if (RTL_R32(PHYAR) & 0x80000000) {
- value = (int) (RTL_R32(PHYAR) & 0xFFFF);
+ RTL_W32(EPHYAR, (reg_addr & EPHYAR_REG_MASK) << EPHYAR_REG_SHIFT);
+
+ for (i = 0; i < 100; i++) {
+ if (RTL_R32(EPHYAR) & EPHYAR_FLAG) {
+ value = RTL_R32(EPHYAR) & EPHYAR_DATA_MASK;
break;
- } else {
- udelay(100);
}
+ udelay(10);
}
+
return value;
}
-#endif
-static void rtl8169_get_mac_version( struct rtl8169_private *tp,
- u32 ioaddr )
+static void rtl_csi_write(void *ioaddr, int addr, int value)
{
- /*
- * The driver currently handles the 8168Bf and the 8168Be identically
- * but they can be identified more specifically through the test below
- * if needed:
- *
- * (RTL_R32(TxConfig) & 0x700000) == 0x500000 ? 8168Bf : 8168Be
- *
- * Same thing for the 8101Eb and the 8101Ec:
- *
- * (RTL_R32(TxConfig) & 0x700000) == 0x200000 ? 8101Eb : 8101Ec
- */
- const struct {
- u32 mask;
- u32 val;
- int mac_version;
- } mac_info[] = {
- /* 8168B family. */
- { 0x7c800000, 0x3c800000, RTL_GIGA_MAC_VER_18 },
- { 0x7cf00000, 0x3c000000, RTL_GIGA_MAC_VER_19 },
- { 0x7cf00000, 0x3c200000, RTL_GIGA_MAC_VER_20 },
- { 0x7c800000, 0x3c000000, RTL_GIGA_MAC_VER_20 },
- /* 8168B family. */
- { 0x7cf00000, 0x38000000, RTL_GIGA_MAC_VER_12 },
- { 0x7cf00000, 0x38500000, RTL_GIGA_MAC_VER_17 },
- { 0x7c800000, 0x38000000, RTL_GIGA_MAC_VER_17 },
- { 0x7c800000, 0x30000000, RTL_GIGA_MAC_VER_11 },
- /* 8101 family. */
- { 0x7cf00000, 0x34000000, RTL_GIGA_MAC_VER_13 },
- { 0x7cf00000, 0x34200000, RTL_GIGA_MAC_VER_16 },
- { 0x7c800000, 0x34000000, RTL_GIGA_MAC_VER_16 },
- /* FIXME: where did these entries come from ? -- FR */
- { 0xfc800000, 0x38800000, RTL_GIGA_MAC_VER_15 },
- { 0xfc800000, 0x30800000, RTL_GIGA_MAC_VER_14 },
- /* 8110 family. */
- { 0xfc800000, 0x98000000, RTL_GIGA_MAC_VER_06 },
- { 0xfc800000, 0x18000000, RTL_GIGA_MAC_VER_05 },
- { 0xfc800000, 0x10000000, RTL_GIGA_MAC_VER_04 },
- { 0xfc800000, 0x04000000, RTL_GIGA_MAC_VER_03 },
- { 0xfc800000, 0x00800000, RTL_GIGA_MAC_VER_02 },
- { 0xfc800000, 0x00000000, RTL_GIGA_MAC_VER_01 },
- { 0x00000000, 0x00000000, RTL_GIGA_MAC_VER_01 } /* Catch-all */
- }, *p = mac_info;
+ unsigned int i;
- unsigned long rv;
+ DBGP ( "rtl_csi_write\n" );
- rv = (RTL_R32(TxConfig));
+ RTL_W32(CSIDR, value);
+ RTL_W32(CSIAR, CSIAR_WRITE_CMD | (addr & CSIAR_ADDR_MASK) |
+ CSIAR_BYTE_ENABLE << CSIAR_BYTE_ENABLE_SHIFT);
- while ((rv & p->mask) != p->val)
- p++;
- tp->mac_version = p->mac_version;
-
- if (p->mask == 0x00000000) {
- DBG("unknown MAC (%08lx)\n", rv);
+ for (i = 0; i < 100; i++) {
+ if (!(RTL_R32(CSIAR) & CSIAR_FLAG))
+ break;
+ udelay(10);
}
}
-#define IORESOURCE_MEM 0x00000200
-
-static int rtl8169_init_board(struct pci_device *pdev)
+static u32 rtl_csi_read(void *ioaddr, int addr)
{
- int i;
-// unsigned long mmio_end, mmio_flags
- unsigned long mmio_start, mmio_len;
- struct rtl8169_private *tp = &tpx;
-
- adjust_pci_device(pdev);
-
- mmio_start = pci_bar_start(pdev, PCI_BASE_ADDRESS_1);
-// mmio_end = pci_resource_end (pdev, 1);
-// mmio_flags = pci_resource_flags (pdev, PCI_BASE_ADDRESS_1);
- mmio_len = pci_bar_size(pdev, PCI_BASE_ADDRESS_1);
-
- // make sure PCI base addr 1 is MMIO
-// if (!(mmio_flags & IORESOURCE_MEM)) {
-// printf ("region #1 not an MMIO resource, aborting\n");
-// return 0;
-// }
-
- // check for weird/broken PCI region reporting
- if (mmio_len < RTL_MIN_IO_SIZE) {
- printf("Invalid PCI region size(s), aborting\n");
- return 0;
- }
-#ifdef RTL8169_USE_IO
- ioaddr = pci_bar_start(pdev, PCI_BASE_ADDRESS_0);
-#else
- // ioremap MMIO region
- ioaddr = (unsigned long) ioremap(mmio_start, mmio_len);
- if (ioaddr == 0) {
- printk("cannot remap MMIO, aborting\n");
- return 0;
- }
-#endif
+ u32 value = ~0x00;
+ unsigned int i;
- tp->mmio_addr = (void*)ioaddr;
- /* Soft reset the chip. */
- RTL_W8(ChipCmd, CmdReset);
+ DBGP ( "rtl_csi_read\n" );
- /* Check that the chip has finished the reset. */
- for (i = 1000; i > 0; i--)
- if ((RTL_R8(ChipCmd) & CmdReset) == 0)
- break;
- else
- udelay(10);
+ RTL_W32(CSIAR, (addr & CSIAR_ADDR_MASK) |
+ CSIAR_BYTE_ENABLE << CSIAR_BYTE_ENABLE_SHIFT);
- /* Identify chip attached to board */
- rtl8169_get_mac_version( tp, ioaddr );
-
- // rtl8169_print_mac_version(tp);
-
- {
- unsigned char val8 =
- (unsigned char) (RTL8169_READ_GMII_REG(ioaddr, 3) &
- 0x000f);
- if (val8 == 0x00) {
- tp->pcfg = RTL_CFG_0;
- } else if (val8 == 0x01) {
- tp->pcfg = RTL_CFG_1;
- } else if (val8 == 0x02) {
- tp->pcfg = RTL_CFG_2;
- } else {
- tp->pcfg = RTL_CFG_2;
+ for (i = 0; i < 100; i++) {
+ if (RTL_R32(CSIAR) & CSIAR_FLAG) {
+ value = RTL_R32(CSIDR);
+ break;
}
+ udelay(10);
}
- /* identify chip attached to board */
-
- for (i = ARRAY_SIZE(rtl_chip_info) - 1; i >= 0; i--)
- if (tp->mac_version == rtl_chip_info[i].mac_version) {
- tp->chipset = i;
- goto match;
- }
- /* if unknown chip, assume array element #0, original RTL-8169 in this case */
- DBG ( "PCI device: unknown chip version, assuming RTL-8169\n" );
- DBG ( "PCI device: TxConfig = %#lX\n", ( unsigned long ) RTL_R32 ( TxConfig ) );
+ return value;
+}
- tp->chipset = 0;
- return 1;
+static void rtl8169_irq_mask_and_ack(void *ioaddr)
+{
+ DBGP ( "rtl8169_irq_mask_and_ack\n" );
- match:
- return 0;
+ RTL_W16(IntrMask, 0x0000);
+ RTL_W16(IntrStatus, 0xffff);
}
-/**************************************************************************
-IRQ - Wait for a frame
-***************************************************************************/
-static void r8169_irq(struct nic *nic __unused, irq_action_t action)
+static unsigned int rtl8169_tbi_reset_pending(void *ioaddr)
{
- int intr_status = 0;
- int interested = RxOverflow | RxFIFOOver | RxErr | RxOK;
+ DBGP ( "rtl8169_tbi_reset_pending\n" );
- switch (action) {
- case DISABLE:
- case ENABLE:
- intr_status = RTL_R16(IntrStatus);
- /* h/w no longer present (hotplug?) or major error,
- bail */
- if (intr_status == 0xFFFF)
- break;
-
- intr_status = intr_status & ~interested;
- if (action == ENABLE)
- intr_status = intr_status | interested;
- RTL_W16(IntrMask, intr_status);
- break;
- case FORCE:
- RTL_W8(TxPoll, (RTL_R8(TxPoll) | 0x01));
- break;
- }
+ return RTL_R32(TBICSR) & TBIReset;
}
-/**************************************************************************
-POLL - Wait for a frame
-***************************************************************************/
-static int r8169_poll(struct nic *nic, int retrieve)
-{
- /* return true if there's an ethernet packet ready to read */
- /* nic->packet should contain data on return */
- /* nic->packetlen should contain length of data */
- int cur_rx;
- unsigned int intr_status = 0;
- struct rtl8169_private *tp = &tpx;
-
- cur_rx = tp->cur_rx;
- if ((tp->RxDescArray[cur_rx].status & OWNbit) == 0) {
- /* There is a packet ready */
- DBG("r8169_poll(): packet ready\n");
- if (!retrieve)
- return 1;
- intr_status = RTL_R16(IntrStatus);
- /* h/w no longer present (hotplug?) or major error,
- bail */
- if (intr_status == 0xFFFF) {
- DBG("r8169_poll(): unknown error\n");
- return 0;
- }
- RTL_W16(IntrStatus, intr_status &
- ~(RxFIFOOver | RxOverflow | RxOK));
-
- if (!(tp->RxDescArray[cur_rx].status & RxRES)) {
- nic->packetlen = (int) (tp->RxDescArray[cur_rx].
- status & 0x00001FFF) - 4;
- memcpy(nic->packet, tp->RxBufferRing[cur_rx],
- nic->packetlen);
- if (cur_rx == NUM_RX_DESC - 1)
- tp->RxDescArray[cur_rx].status =
- (OWNbit | EORbit) + RX_BUF_SIZE;
- else
- tp->RxDescArray[cur_rx].status =
- OWNbit + RX_BUF_SIZE;
- tp->RxDescArray[cur_rx].buf_addr =
- virt_to_bus(tp->RxBufferRing[cur_rx]);
- tp->RxDescArray[cur_rx].buf_Haddr = 0;
- } else
- printf("Error Rx");
- /* FIXME: shouldn't I reset the status on an error */
- cur_rx = (cur_rx + 1) % NUM_RX_DESC;
- tp->cur_rx = cur_rx;
- RTL_W16(IntrStatus, intr_status &
- (RxFIFOOver | RxOverflow | RxOK));
-
- return 1;
+static unsigned int rtl8169_xmii_reset_pending(void *ioaddr)
+{
+ DBGP ( "rtl8169_xmii_reset_pending\n" );
- }
- tp->cur_rx = cur_rx;
- /* FIXME: There is no reason to do this as cur_rx did not change */
-
- return (0); /* initially as this is called to flush the input */
-
-}
-
-/**************************************************************************
-TRANSMIT - Transmit a frame
-***************************************************************************/
-static void r8169_transmit(struct nic *nic, const char *d, /* Destination */
- unsigned int t, /* Type */
- unsigned int s, /* size */
- const char *p)
-{ /* Packet */
- /* send the packet to destination */
-
- u16 nstype;
- u32 to;
- u8 *ptxb;
- struct rtl8169_private *tp = &tpx;
- int entry = tp->cur_tx % NUM_TX_DESC;
-
- /* point to the current txb incase multiple tx_rings are used */
- ptxb = tp->Tx_skbuff[entry * MAX_ETH_FRAME_SIZE];
- memcpy(ptxb, d, ETH_ALEN);
- memcpy(ptxb + ETH_ALEN, nic->node_addr, ETH_ALEN);
- nstype = htons((u16) t);
- memcpy(ptxb + 2 * ETH_ALEN, (u8 *) & nstype, 2);
- memcpy(ptxb + ETH_HLEN, p, s);
- s += ETH_HLEN;
- s &= 0x0FFF;
- while (s < ETH_ZLEN)
- ptxb[s++] = '\0';
-
- tp->TxDescArray[entry].buf_addr = virt_to_bus(ptxb);
- tp->TxDescArray[entry].buf_Haddr = 0;
- if (entry != (NUM_TX_DESC - 1))
- tp->TxDescArray[entry].status =
- (OWNbit | FSbit | LSbit) | ((s > ETH_ZLEN) ? s :
- ETH_ZLEN);
- else
- tp->TxDescArray[entry].status =
- (OWNbit | EORbit | FSbit | LSbit) | ((s > ETH_ZLEN) ? s
- : ETH_ZLEN);
- RTL_W8(TxPoll, 0x40); /* set polling bit */
-
- tp->cur_tx++;
- to = currticks() + TX_TIMEOUT;
- while ((tp->TxDescArray[entry].status & OWNbit) && (currticks() < to)); /* wait */
-
- if (currticks() >= to) {
- printf("TX Time Out");
- }
+ return mdio_read(ioaddr, MII_BMCR) & BMCR_RESET;
}
-static void rtl8169_set_rx_mode(struct nic *nic __unused)
+static unsigned int rtl8169_tbi_link_ok(void *ioaddr)
{
- u32 mc_filter[2]; /* Multicast hash filter */
- int rx_mode;
- u32 tmp = 0;
- struct rtl8169_private *tp = &tpx;
+ DBGP ( "rtl8169_tbi_link_ok\n" );
- /* IFF_ALLMULTI */
- /* Too many to filter perfectly -- accept all multicasts. */
- rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
- mc_filter[1] = mc_filter[0] = 0xffffffff;
+ return RTL_R32(TBICSR) & TBILinkOk;
+}
- tmp =
- rtl8169_rx_config | rx_mode | (RTL_R32(RxConfig) &
- rtl_chip_info[tp->chipset].
- RxConfigMask);
+static unsigned int rtl8169_xmii_link_ok(void *ioaddr)
+{
+ DBGP ( "rtl8169_xmii_link_ok\n" );
- RTL_W32(RxConfig, tmp);
- RTL_W32(MAR0 + 0, mc_filter[0]);
- RTL_W32(MAR0 + 4, mc_filter[1]);
+ return RTL_R8(PHYstatus) & LinkStatus;
}
-static void rtl8169_hw_start(struct nic *nic)
+
+static void rtl8169_tbi_reset_enable(void *ioaddr)
{
- u32 i;
- struct rtl8169_private *tp = &tpx;
+ DBGP ( "rtl8169_tbi_reset_enable\n" );
- /* Soft reset the chip. */
- RTL_W8(ChipCmd, CmdReset);
+ RTL_W32(TBICSR, RTL_R32(TBICSR) | TBIReset);
+}
- /* Check that the chip has finished the reset. */
- for (i = 1000; i > 0; i--) {
- if ((RTL_R8(ChipCmd) & CmdReset) == 0)
- break;
- else
- udelay(10);
- }
+static void rtl8169_xmii_reset_enable(void *ioaddr)
+{
+ unsigned int val;
- RTL_W8(Cfg9346, Cfg9346_Unlock);
- RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
- RTL_W8(ETThReg, ETTh);
+ DBGP ( "rtl8169_xmii_reset_enable\n" );
- /* For gigabit rtl8169 */
- RTL_W16(RxMaxSize, RxPacketMaxSize);
+ val = mdio_read(ioaddr, MII_BMCR) | BMCR_RESET;
+ mdio_write(ioaddr, MII_BMCR, val & 0xffff);
+}
- /* Set Rx Config register */
- i = rtl8169_rx_config | (RTL_R32(RxConfig) &
- rtl_chip_info[tp->chipset].RxConfigMask);
- RTL_W32(RxConfig, i);
+static int rtl8169_set_speed_tbi(struct net_device *dev,
+ u8 autoneg, u16 speed, u8 duplex)
+{
+ struct rtl8169_private *tp = netdev_priv(dev);
+ void *ioaddr = tp->mmio_addr;
+ int ret = 0;
+ u32 reg;
+
+ DBGP ( "rtl8169_set_speed_tbi\n" );
+
+ reg = RTL_R32(TBICSR);
+ if ((autoneg == AUTONEG_DISABLE) && (speed == SPEED_1000) &&
+ (duplex == DUPLEX_FULL)) {
+ RTL_W32(TBICSR, reg & ~(TBINwEnable | TBINwRestart));
+ } else if (autoneg == AUTONEG_ENABLE)
+ RTL_W32(TBICSR, reg | TBINwEnable | TBINwRestart);
+ else {
+ DBG ( "incorrect speed setting refused in TBI mode\n" );
+ ret = -EOPNOTSUPP;
+ }
+ return ret;
+}
- /* Set DMA burst size and Interframe Gap Time */
- RTL_W32(TxConfig,
- (TX_DMA_BURST << TxDMAShift) | (InterFrameGap <<
- TxInterFrameGapShift));
+static int rtl8169_set_speed_xmii(struct net_device *dev,
+ u8 autoneg, u16 speed, u8 duplex)
+{
+ struct rtl8169_private *tp = netdev_priv(dev);
+ void *ioaddr = tp->mmio_addr;
+ int auto_nego, giga_ctrl;
+ DBGP ( "rtl8169_set_speed_xmii\n" );
- RTL_W16(CPlusCmd, RTL_R16(CPlusCmd));
+ auto_nego = mdio_read(ioaddr, MII_ADVERTISE);
+ auto_nego &= ~(ADVERTISE_10HALF | ADVERTISE_10FULL |
+ ADVERTISE_100HALF | ADVERTISE_100FULL);
+ giga_ctrl = mdio_read(ioaddr, MII_CTRL1000);
+ giga_ctrl &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
- if (tp->mac_version == RTL_GIGA_MAC_VER_02 || tp->mac_version == RTL_GIGA_MAC_VER_03) {
- RTL_W16(CPlusCmd,
- (RTL_R16(CPlusCmd) | (1 << 14) | (1 << 3)));
- DBG
- ("Set MAC Reg C+CR Offset 0xE0: bit-3 and bit-14\n");
+ if (autoneg == AUTONEG_ENABLE) {
+ auto_nego |= (ADVERTISE_10HALF | ADVERTISE_10FULL |
+ ADVERTISE_100HALF | ADVERTISE_100FULL);
+ giga_ctrl |= ADVERTISE_1000FULL | ADVERTISE_1000HALF;
} else {
- RTL_W16(CPlusCmd, (RTL_R16(CPlusCmd) | (1 << 3)));
- DBG("Set MAC Reg C+CR Offset 0xE0: bit-3.\n");
+ if (speed == SPEED_10)
+ auto_nego |= ADVERTISE_10HALF | ADVERTISE_10FULL;
+ else if (speed == SPEED_100)
+ auto_nego |= ADVERTISE_100HALF | ADVERTISE_100FULL;
+ else if (speed == SPEED_1000)
+ giga_ctrl |= ADVERTISE_1000FULL | ADVERTISE_1000HALF;
+
+ if (duplex == DUPLEX_HALF)
+ auto_nego &= ~(ADVERTISE_10FULL | ADVERTISE_100FULL);
+
+ if (duplex == DUPLEX_FULL)
+ auto_nego &= ~(ADVERTISE_10HALF | ADVERTISE_100HALF);
+
+ /* This tweak comes straight from Realtek's driver. */
+ if ((speed == SPEED_100) && (duplex == DUPLEX_HALF) &&
+ ((tp->mac_version == RTL_GIGA_MAC_VER_13) ||
+ (tp->mac_version == RTL_GIGA_MAC_VER_16))) {
+ auto_nego = ADVERTISE_100HALF | ADVERTISE_CSMA;
+ }
}
- {
- //RTL_W16(IntrMitigate, 0x1517);
- //RTL_W16(IntrMitigate, 0x152a);
- //RTL_W16(IntrMitigate, 0x282a);
- RTL_W16(IntrMitigate, 0x0000);
+ /* The 8100e/8101e/8102e do Fast Ethernet only. */
+ if ((tp->mac_version == RTL_GIGA_MAC_VER_07) ||
+ (tp->mac_version == RTL_GIGA_MAC_VER_08) ||
+ (tp->mac_version == RTL_GIGA_MAC_VER_09) ||
+ (tp->mac_version == RTL_GIGA_MAC_VER_10) ||
+ (tp->mac_version == RTL_GIGA_MAC_VER_13) ||
+ (tp->mac_version == RTL_GIGA_MAC_VER_14) ||
+ (tp->mac_version == RTL_GIGA_MAC_VER_15) ||
+ (tp->mac_version == RTL_GIGA_MAC_VER_16)) {
+ if ((giga_ctrl & (ADVERTISE_1000FULL | ADVERTISE_1000HALF))) {
+ DBG ( "PHY does not support 1000Mbps.\n" );
+ }
+ giga_ctrl &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
}
- tp->cur_rx = 0;
-
- RTL_W32(TxDescAddrLow, virt_to_le32desc(tp->TxDescArray));
- RTL_W32(TxDescAddrHigh, virt_to_le32desc(NULL));
- RTL_W32(RxDescAddrLow, virt_to_le32desc(tp->RxDescArray));
- RTL_W32(RxDescAddrHigh, virt_to_le32desc(NULL));
- RTL_W8(Cfg9346, Cfg9346_Lock);
- udelay(10);
-
- RTL_W32(RxMissed, 0);
-
- rtl8169_set_rx_mode(nic);
-
- /* no early-rx interrupts */
- RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xF000);
+ auto_nego |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
+
+ if ((tp->mac_version == RTL_GIGA_MAC_VER_11) ||
+ (tp->mac_version == RTL_GIGA_MAC_VER_12) ||
+ (tp->mac_version >= RTL_GIGA_MAC_VER_17)) {
+ /*
+ * Wake up the PHY.
+ * Vendor specific (0x1f) and reserved (0x0e) MII registers.
+ */
+ mdio_write(ioaddr, 0x1f, 0x0000);
+ mdio_write(ioaddr, 0x0e, 0x0000);
+ }
- RTL_W16(IntrMask, rtl8169_intr_mask);
+ tp->phy_auto_nego_reg = auto_nego;
+ tp->phy_1000_ctrl_reg = giga_ctrl;
+ mdio_write(ioaddr, MII_ADVERTISE, auto_nego);
+ mdio_write(ioaddr, MII_CTRL1000, giga_ctrl);
+ mdio_write(ioaddr, MII_BMCR, BMCR_ANENABLE | BMCR_ANRESTART);
+ return 0;
}
-static void rtl8169_init_ring(struct nic *nic __unused)
+static int rtl8169_set_speed(struct net_device *dev,
+ u8 autoneg, u16 speed, u8 duplex)
{
- int i;
- struct rtl8169_private *tp = &tpx;
+ struct rtl8169_private *tp = netdev_priv(dev);
+ int ret;
- tp->cur_rx = 0;
- tp->cur_tx = 0;
- memset(tp->TxDescArray, 0x0, NUM_TX_DESC * sizeof(struct TxDesc));
- memset(tp->RxDescArray, 0x0, NUM_RX_DESC * sizeof(struct RxDesc));
+ DBGP ( "rtl8169_set_speed\n" );
- for (i = 0; i < NUM_TX_DESC; i++) {
- tp->Tx_skbuff[i] = &txb[i];
- }
+ ret = tp->set_speed(dev, autoneg, speed, duplex);
- for (i = 0; i < NUM_RX_DESC; i++) {
- if (i == (NUM_RX_DESC - 1))
- tp->RxDescArray[i].status =
- (OWNbit | EORbit) | RX_BUF_SIZE;
- else
- tp->RxDescArray[i].status = OWNbit | RX_BUF_SIZE;
-
- tp->RxBufferRing[i] = &rxb[i * RX_BUF_SIZE];
- tp->RxDescArray[i].buf_addr =
- virt_to_bus(tp->RxBufferRing[i]);
- tp->RxDescArray[i].buf_Haddr = 0;
- }
+ return ret;
}
-/**************************************************************************
-RESET - Finish setting up the ethernet interface
-***************************************************************************/
-static void r8169_reset(struct nic *nic)
+static void rtl8169_write_gmii_reg_bit(void *ioaddr, int reg,
+ int bitnum, int bitval)
{
- int i;
- struct rtl8169_private *tp = &tpx;
-
- tp->TxDescArray = tx_ring;
- tp->RxDescArray = rx_ring;
-
- rtl8169_init_ring(nic);
- rtl8169_hw_start(nic);
- /* Construct a perfect filter frame with the mac address as first match
- * and broadcast for all others */
- for (i = 0; i < 192; i++)
- txb[i] = 0xFF;
-
- txb[0] = nic->node_addr[0];
- txb[1] = nic->node_addr[1];
- txb[2] = nic->node_addr[2];
- txb[3] = nic->node_addr[3];
- txb[4] = nic->node_addr[4];
- txb[5] = nic->node_addr[5];
-}
-
-/**************************************************************************
-DISABLE - Turn off ethernet interface
-***************************************************************************/
-static void r8169_disable ( struct nic *nic __unused ) {
- int i;
- struct rtl8169_private *tp = &tpx;
+ int val;
- /* Stop the chip's Tx and Rx DMA processes. */
- RTL_W8(ChipCmd, 0x00);
-
- /* Disable interrupts by clearing the interrupt mask. */
- RTL_W16(IntrMask, 0x0000);
+ DBGP ( "rtl8169_write_gmii_reg_bit\n" );
- RTL_W32(RxMissed, 0);
-
- tp->TxDescArray = NULL;
- tp->RxDescArray = NULL;
- for (i = 0; i < NUM_RX_DESC; i++) {
- tp->RxBufferRing[i] = NULL;
- }
+ val = mdio_read(ioaddr, reg);
+ val = (bitval == 1) ?
+ val | (bitval << bitnum) : val & ~(0x0001 << bitnum);
+ mdio_write(ioaddr, reg, val & 0xffff);
}
-static struct nic_operations r8169_operations = {
- .connect = dummy_connect,
- .poll = r8169_poll,
- .transmit = r8169_transmit,
- .irq = r8169_irq,
-
-};
-
-static struct pci_device_id r8169_nics[] = {
- PCI_ROM(0x10ec, 0x8169, "r8169", "RealTek RTL8169 Gigabit Ethernet"),
- PCI_ROM(0x16ec, 0x0116, "usr-r8169", "US Robotics RTL8169 Gigabit Ethernet"),
- PCI_ROM(0x1186, 0x4300, "dlink-r8169", "D-Link RTL8169 Gigabit Ethernet"),
- PCI_ROM(0x1737, 0x1032, "linksys-r8169", "Linksys RTL8169 Gigabit Ethernet"),
- PCI_ROM(0x10ec, 0x8129, "r8169-8129", "RealTek RT8129 Fast Ethernet Adapter"),
- PCI_ROM(0x10ec, 0x8136, "r8169-8101e", "RealTek RTL8101E PCI Express Fast Ethernet controller"),
- PCI_ROM(0x10ec, 0x8167, "r8169-8110sc/8169sc", "RealTek RTL-8110SC/8169SC Gigabit Ethernet"),
- PCI_ROM(0x10ec, 0x8168, "r8169-8168b", "RealTek RTL8111/8168B PCI Express Gigabit Ethernet controller"),
-};
-
-PCI_DRIVER ( r8169_driver, r8169_nics, PCI_NO_CLASS );
-
-/**************************************************************************
-PROBE - Look for an adapter, this routine's visible to the outside
-***************************************************************************/
-
-#define board_found 1
-#define valid_link 0
-static int r8169_probe ( struct nic *nic, struct pci_device *pci ) {
-
- static int board_idx = -1;
- static int printed_version = 0;
- struct rtl8169_private *tp = &tpx;
- int i, rc;
- int option = -1, Cap10_100 = 0, Cap1000 = 0;
-
- printf ( "r8169.c: Found %s, Vendor=%hX Device=%hX\n",
- pci->driver_name, pci->vendor, pci->device );
-
- board_idx++;
-
- printed_version = 1;
-
- /* Quick and very dirty hack to get r8169 driver working
- * again, pre-rewrite
+static void rtl8169_get_mac_version(struct rtl8169_private *tp,
+ void *ioaddr)
+{
+ /*
+ * The driver currently handles the 8168Bf and the 8168Be identically
+ * but they can be identified more specifically through the test below
+ * if needed:
+ *
+ * (RTL_R32(TxConfig) & 0x700000) == 0x500000 ? 8168Bf : 8168Be
+ *
+ * Same thing for the 8101Eb and the 8101Ec:
+ *
+ * (RTL_R32(TxConfig) & 0x700000) == 0x200000 ? 8101Eb : 8101Ec
*/
- if ( ! r8169_bufs )
- r8169_bufs = malloc_dma ( sizeof ( *r8169_bufs ), 256 );
- if ( ! r8169_bufs )
- return 0;
- memset ( r8169_bufs, 0, sizeof ( *r8169_bufs ) );
-
- rc = rtl8169_init_board(pci); /* Return code is meaningless */
-
- /* Get MAC address. FIXME: read EEPROM */
- for (i = 0; i < MAC_ADDR_LEN; i++)
- nic->node_addr[i] = RTL_R8(MAC0 + i);
-
- DBG ( "%s: Identified chip type is '%s'.\n", pci->driver_name,
- rtl_chip_info[tp->chipset].name );
-
- /* Print out some hardware info */
- DBG ( "%s: %s at ioaddr %#hx, ", pci->driver_name, eth_ntoa ( nic->node_addr ),
- (unsigned int) ioaddr );
+ const struct {
+ u32 mask;
+ u32 val;
+ int mac_version;
+ } mac_info[] = {
+ /* 8168D family. */
+ { 0x7c800000, 0x28000000, RTL_GIGA_MAC_VER_25 },
+
+ /* 8168C family. */
+ { 0x7cf00000, 0x3ca00000, RTL_GIGA_MAC_VER_24 },
+ { 0x7cf00000, 0x3c900000, RTL_GIGA_MAC_VER_23 },
+ { 0x7cf00000, 0x3c800000, RTL_GIGA_MAC_VER_18 },
+ { 0x7c800000, 0x3c800000, RTL_GIGA_MAC_VER_24 },
+ { 0x7cf00000, 0x3c000000, RTL_GIGA_MAC_VER_19 },
+ { 0x7cf00000, 0x3c200000, RTL_GIGA_MAC_VER_20 },
+ { 0x7cf00000, 0x3c300000, RTL_GIGA_MAC_VER_21 },
+ { 0x7cf00000, 0x3c400000, RTL_GIGA_MAC_VER_22 },
+ { 0x7c800000, 0x3c000000, RTL_GIGA_MAC_VER_22 },
- /* Config PHY */
- rtl8169_hw_phy_config(nic);
-
- DBG("Set MAC Reg C+CR Offset 0x82h = 0x01h\n");
- RTL_W8(0x82, 0x01);
+ /* 8168B family. */
+ { 0x7cf00000, 0x38000000, RTL_GIGA_MAC_VER_12 },
+ { 0x7cf00000, 0x38500000, RTL_GIGA_MAC_VER_17 },
+ { 0x7c800000, 0x38000000, RTL_GIGA_MAC_VER_17 },
+ { 0x7c800000, 0x30000000, RTL_GIGA_MAC_VER_11 },
- pci_write_config_byte(pci, PCI_LATENCY_TIMER, 0x40);
+ /* 8101 family. */
+ { 0x7cf00000, 0x34a00000, RTL_GIGA_MAC_VER_09 },
+ { 0x7cf00000, 0x24a00000, RTL_GIGA_MAC_VER_09 },
+ { 0x7cf00000, 0x34900000, RTL_GIGA_MAC_VER_08 },
+ { 0x7cf00000, 0x24900000, RTL_GIGA_MAC_VER_08 },
+ { 0x7cf00000, 0x34800000, RTL_GIGA_MAC_VER_07 },
+ { 0x7cf00000, 0x24800000, RTL_GIGA_MAC_VER_07 },
+ { 0x7cf00000, 0x34000000, RTL_GIGA_MAC_VER_13 },
+ { 0x7cf00000, 0x34300000, RTL_GIGA_MAC_VER_10 },
+ { 0x7cf00000, 0x34200000, RTL_GIGA_MAC_VER_16 },
+ { 0x7c800000, 0x34800000, RTL_GIGA_MAC_VER_09 },
+ { 0x7c800000, 0x24800000, RTL_GIGA_MAC_VER_09 },
+ { 0x7c800000, 0x34000000, RTL_GIGA_MAC_VER_16 },
+ /* FIXME: where did these entries come from ? -- FR */
+ { 0xfc800000, 0x38800000, RTL_GIGA_MAC_VER_15 },
+ { 0xfc800000, 0x30800000, RTL_GIGA_MAC_VER_14 },
- if (tp->mac_version <= RTL_GIGA_MAC_VER_06)
- pci_write_config_byte(pci, PCI_CACHE_LINE_SIZE, 0x08);
+ /* 8110 family. */
+ { 0xfc800000, 0x98000000, RTL_GIGA_MAC_VER_06 },
+ { 0xfc800000, 0x18000000, RTL_GIGA_MAC_VER_05 },
+ { 0xfc800000, 0x10000000, RTL_GIGA_MAC_VER_04 },
+ { 0xfc800000, 0x04000000, RTL_GIGA_MAC_VER_03 },
+ { 0xfc800000, 0x00800000, RTL_GIGA_MAC_VER_02 },
+ { 0xfc800000, 0x00000000, RTL_GIGA_MAC_VER_01 },
- if (tp->mac_version == RTL_GIGA_MAC_VER_02) {
- DBG("Set MAC Reg C+CR Offset 0x82h = 0x01h\n");
- RTL_W8(0x82, 0x01);
- DBG("Set PHY Reg 0x0bh = 0x00h\n");
- RTL8169_WRITE_GMII_REG(ioaddr, 0x0b, 0x0000); //w 0x0b 15 0 0
- }
+ { 0x00000000, 0x00000000, RTL_GIGA_MAC_VER_01 } /* Catch-all */
+ }, *p = mac_info;
+ u32 reg;
- r8169_reset(nic);
-
- /* if TBI is not endbled */
- if (!(RTL_R8(PHYstatus) & TBI_Enable)) {
- int val = RTL8169_READ_GMII_REG(ioaddr, PHY_AUTO_NEGO_REG);
-
-#ifdef RTL8169_HW_FLOW_CONTROL_SUPPORT
- val |= PHY_Cap_PAUSE | PHY_Cap_ASYM_PAUSE;
-#endif //end #define RTL8169_HW_FLOW_CONTROL_SUPPORT
-
- /* Force RTL8169 in 10/100/1000 Full/Half mode. */
- if (option > 0) {
- printf(" Force-mode Enabled.\n");
- Cap10_100 = 0, Cap1000 = 0;
- switch (option) {
- case _10_Half:
- Cap10_100 = PHY_Cap_10_Half;
- Cap1000 = PHY_Cap_Null;
- break;
- case _10_Full:
- Cap10_100 = PHY_Cap_10_Full;
- Cap1000 = PHY_Cap_Null;
- break;
- case _100_Half:
- Cap10_100 = PHY_Cap_100_Half;
- Cap1000 = PHY_Cap_Null;
- break;
- case _100_Full:
- Cap10_100 = PHY_Cap_100_Full;
- Cap1000 = PHY_Cap_Null;
- break;
- case _1000_Full:
- Cap10_100 = PHY_Cap_Null;
- Cap1000 = PHY_Cap_1000_Full;
- break;
- default:
- break;
- }
- RTL8169_WRITE_GMII_REG(ioaddr, PHY_AUTO_NEGO_REG, Cap10_100 | (val & 0xC1F)); //leave PHY_AUTO_NEGO_REG bit4:0 unchanged
- RTL8169_WRITE_GMII_REG(ioaddr, PHY_1000_CTRL_REG,
- Cap1000);
- } else {
- DBG ( "%s: Auto-negotiation Enabled.\n", pci->driver_name );
-
- // enable 10/100 Full/Half Mode, leave PHY_AUTO_NEGO_REG bit4:0 unchanged
- RTL8169_WRITE_GMII_REG(ioaddr, PHY_AUTO_NEGO_REG,
- PHY_Cap_10_Half |
- PHY_Cap_10_Full |
- PHY_Cap_100_Half |
- PHY_Cap_100_Full | (val &
- 0xC1F));
-
- // enable 1000 Full Mode
-// RTL8169_WRITE_GMII_REG( ioaddr, PHY_1000_CTRL_REG, PHY_Cap_1000_Full );
- RTL8169_WRITE_GMII_REG(ioaddr, PHY_1000_CTRL_REG, PHY_Cap_1000_Full | PHY_Cap_1000_Half); //rtl8168
-
- } // end of if( option > 0 )
-
- // Enable auto-negotiation and restart auto-nigotiation
- RTL8169_WRITE_GMII_REG(ioaddr, PHY_CTRL_REG,
- PHY_Enable_Auto_Nego |
- PHY_Restart_Auto_Nego);
- udelay(100);
-
- // wait for auto-negotiation process
- for (i = 10000; i > 0; i--) {
- //check if auto-negotiation complete
- if (RTL8169_READ_GMII_REG(ioaddr, PHY_STAT_REG) &
- PHY_Auto_Neco_Comp) {
- udelay(100);
- option = RTL_R8(PHYstatus);
- if (option & _1000bpsF) {
- printf
- ("1000Mbps Full-duplex operation.\n");
- } else {
- printf
- ("%sMbps %s-duplex operation.\n",
- (option & _100bps) ? "100" :
- "10",
- (option & FullDup) ? "Full" :
- "Half");
- }
- break;
- } else {
- udelay(100);
- } // end of if( RTL8169_READ_GMII_REG(ioaddr, 1) & 0x20 )
- } // end for-loop to wait for auto-negotiation process
+ DBGP ( "rtl8169_get_mac_version\n" );
+ reg = RTL_R32(TxConfig);
+ while ((reg & p->mask) != p->val)
+ p++;
+ tp->mac_version = p->mac_version;
- } else {
- udelay(100);
- printf
- ("%s: 1000Mbps Full-duplex operation, TBI Link %s!\n",
- pci->driver_name,
- (RTL_R32(TBICSR) & TBILinkOK) ? "OK" : "Failed");
+ DBG ( "tp->mac_version = %d\n", tp->mac_version );
+ if (p->mask == 0x00000000) {
+ DBG ( "unknown MAC (%08lx)\n", reg );
}
-
- r8169_reset(nic);
-
- /* point to NIC specific routines */
- nic->nic_op = &r8169_operations;
-
- nic->irqno = pci->irq;
- nic->ioaddr = ioaddr;
-
- return 1;
-}
-
-//======================================================================================================
-/*
-static void rtl8169_hw_PHY_reset(struct nic *nic __unused)
-{
- int val, phy_reset_expiretime = 50;
- struct rtl8169_private *priv = dev->priv;
- unsigned long ioaddr = priv->ioaddr;
-
- DBG("%s: Reset RTL8169s PHY\n", dev->name);
-
- val = ( RTL8169_READ_GMII_REG( ioaddr, 0 ) | 0x8000 ) & 0xffff;
- RTL8169_WRITE_GMII_REG( ioaddr, 0, val );
-
- do //waiting for phy reset
- {
- if( RTL8169_READ_GMII_REG( ioaddr, 0 ) & 0x8000 ){
- phy_reset_expiretime --;
- udelay(100);
- }
- else{
- break;
- }
- }while( phy_reset_expiretime >= 0 );
-
- assert( phy_reset_expiretime > 0 );
}
-*/
-
struct phy_reg {
u16 reg;
u16 val;
@@ -1161,8 +436,10 @@ struct phy_reg {
static void rtl_phy_write(void *ioaddr, struct phy_reg *regs, int len)
{
+ DBGP ( "rtl_phy_write\n" );
+
while (len-- > 0) {
- RTL8169_WRITE_GMII_REG((u32)ioaddr, regs->reg, regs->val);
+ mdio_write(ioaddr, regs->reg, regs->val);
regs++;
}
}
@@ -1201,22 +478,24 @@ static void rtl8169s_hw_phy_config(void *ioaddr)
}, *p = phy_magic;
unsigned int i;
- RTL8169_WRITE_GMII_REG((u32)ioaddr, 0x1f, 0x0001); //w 31 2 0 1
- RTL8169_WRITE_GMII_REG((u32)ioaddr, 0x15, 0x1000); //w 21 15 0 1000
- RTL8169_WRITE_GMII_REG((u32)ioaddr, 0x18, 0x65c7); //w 24 15 0 65c7
- RTL8169_WRITE_GMII_REG_BIT((u32)ioaddr, 4, 11, 0); //w 4 11 11 0
+ DBGP ( "rtl8169s_hw_phy_config\n" );
+
+ mdio_write(ioaddr, 0x1f, 0x0001); //w 31 2 0 1
+ mdio_write(ioaddr, 0x15, 0x1000); //w 21 15 0 1000
+ mdio_write(ioaddr, 0x18, 0x65c7); //w 24 15 0 65c7
+ rtl8169_write_gmii_reg_bit(ioaddr, 4, 11, 0); //w 4 11 11 0
for (i = 0; i < ARRAY_SIZE(phy_magic); i++, p++) {
int val, pos = 4;
- val = (RTL8169_READ_GMII_REG((u32)ioaddr, pos) & 0x0fff) | (p->regs[0] & 0xffff);
- RTL8169_WRITE_GMII_REG((u32)ioaddr, pos, val);
+ val = (mdio_read(ioaddr, pos) & 0x0fff) | (p->regs[0] & 0xffff);
+ mdio_write(ioaddr, pos, val);
while (--pos >= 0)
- RTL8169_WRITE_GMII_REG((u32)ioaddr, pos, p->regs[4 - pos] & 0xffff);
- RTL8169_WRITE_GMII_REG_BIT((u32)ioaddr, 4, 11, 1); //w 4 11 11 1
- RTL8169_WRITE_GMII_REG_BIT((u32)ioaddr, 4, 11, 0); //w 4 11 11 0
+ mdio_write(ioaddr, pos, p->regs[4 - pos] & 0xffff);
+ rtl8169_write_gmii_reg_bit(ioaddr, 4, 11, 1); //w 4 11 11 1
+ rtl8169_write_gmii_reg_bit(ioaddr, 4, 11, 0); //w 4 11 11 0
}
- RTL8169_WRITE_GMII_REG((u32)ioaddr, 0x1f, 0x0000); //w 31 2 0 0
+ mdio_write(ioaddr, 0x1f, 0x0000); //w 31 2 0 0
}
static void rtl8169sb_hw_phy_config(void *ioaddr)
@@ -1227,10 +506,40 @@ static void rtl8169sb_hw_phy_config(void *ioaddr)
{ 0x1f, 0x0000 }
};
+ DBGP ( "rtl8169sb_hw_phy_config\n" );
+
+ rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+}
+
+static void rtl8168bb_hw_phy_config(void *ioaddr)
+{
+ struct phy_reg phy_reg_init[] = {
+ { 0x10, 0xf41b },
+ { 0x1f, 0x0000 }
+ };
+
+ mdio_write(ioaddr, 0x1f, 0x0001);
+ mdio_patch(ioaddr, 0x16, 1 << 0);
+
+ DBGP ( "rtl8168bb_hw_phy_config\n" );
+
+ rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+}
+
+static void rtl8168bef_hw_phy_config(void *ioaddr)
+{
+ struct phy_reg phy_reg_init[] = {
+ { 0x1f, 0x0001 },
+ { 0x10, 0xf41b },
+ { 0x1f, 0x0000 }
+ };
+
+ DBGP ( "rtl8168bef_hw_phy_config\n" );
+
rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
}
-static void rtl8168cp_hw_phy_config(void *ioaddr)
+static void rtl8168cp_1_hw_phy_config(void *ioaddr)
{
struct phy_reg phy_reg_init[] = {
{ 0x1f, 0x0000 },
@@ -1240,10 +549,29 @@ static void rtl8168cp_hw_phy_config(void *ioaddr)
{ 0x1f, 0x0000 }
};
+ DBGP ( "rtl8168cp_1_hw_phy_config\n" );
+
+ rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+}
+
+static void rtl8168cp_2_hw_phy_config(void *ioaddr)
+{
+ struct phy_reg phy_reg_init[] = {
+ { 0x1f, 0x0001 },
+ { 0x1d, 0x3d98 },
+ { 0x1f, 0x0000 }
+ };
+
+ DBGP ( "rtl8168cp_2_hw_phy_config\n" );
+
+ mdio_write(ioaddr, 0x1f, 0x0000);
+ mdio_patch(ioaddr, 0x14, 1 << 5);
+ mdio_patch(ioaddr, 0x0d, 1 << 5);
+
rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
}
-static void rtl8168c_hw_phy_config(void *ioaddr)
+static void rtl8168c_1_hw_phy_config(void *ioaddr)
{
struct phy_reg phy_reg_init[] = {
{ 0x1f, 0x0001 },
@@ -1259,33 +587,180 @@ static void rtl8168c_hw_phy_config(void *ioaddr)
{ 0x1f, 0x0003 },
{ 0x12, 0xc096 },
{ 0x16, 0x000a },
- { 0x1f, 0x0000 }
+ { 0x1f, 0x0000 },
+ { 0x1f, 0x0000 },
+ { 0x09, 0x2000 },
+ { 0x09, 0x0000 }
};
+ DBGP ( "rtl8168c_1_hw_phy_config\n" );
+
rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+
+ mdio_patch(ioaddr, 0x14, 1 << 5);
+ mdio_patch(ioaddr, 0x0d, 1 << 5);
+ mdio_write(ioaddr, 0x1f, 0x0000);
}
-static void rtl8168cx_hw_phy_config(void *ioaddr)
+static void rtl8168c_2_hw_phy_config(void *ioaddr)
{
struct phy_reg phy_reg_init[] = {
- { 0x1f, 0x0000 },
+ { 0x1f, 0x0001 },
{ 0x12, 0x2300 },
+ { 0x03, 0x802f },
+ { 0x02, 0x4f02 },
+ { 0x01, 0x0409 },
+ { 0x00, 0xf099 },
+ { 0x04, 0x9800 },
+ { 0x04, 0x9000 },
+ { 0x1d, 0x3d98 },
+ { 0x1f, 0x0002 },
+ { 0x0c, 0x7eb8 },
+ { 0x06, 0x0761 },
{ 0x1f, 0x0003 },
{ 0x16, 0x0f0a },
- { 0x1f, 0x0000 },
+ { 0x1f, 0x0000 }
+ };
+
+ DBGP ( "rtl8168c_2_hw_phy_config\n" );
+
+ rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+
+ mdio_patch(ioaddr, 0x16, 1 << 0);
+ mdio_patch(ioaddr, 0x14, 1 << 5);
+ mdio_patch(ioaddr, 0x0d, 1 << 5);
+ mdio_write(ioaddr, 0x1f, 0x0000);
+}
+
+static void rtl8168c_3_hw_phy_config(void *ioaddr)
+{
+ struct phy_reg phy_reg_init[] = {
+ { 0x1f, 0x0001 },
+ { 0x12, 0x2300 },
+ { 0x1d, 0x3d98 },
{ 0x1f, 0x0002 },
{ 0x0c, 0x7eb8 },
+ { 0x06, 0x5461 },
+ { 0x1f, 0x0003 },
+ { 0x16, 0x0f0a },
{ 0x1f, 0x0000 }
};
+ DBGP ( "rtl8168c_3_hw_phy_config\n" );
+
+ rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+
+ mdio_patch(ioaddr, 0x16, 1 << 0);
+ mdio_patch(ioaddr, 0x14, 1 << 5);
+ mdio_patch(ioaddr, 0x0d, 1 << 5);
+ mdio_write(ioaddr, 0x1f, 0x0000);
+}
+
+static void rtl8168c_4_hw_phy_config(void *ioaddr)
+{
+ DBGP ( "rtl8168c_4_hw_phy_config\n" );
+
+ rtl8168c_3_hw_phy_config(ioaddr);
+}
+
+static void rtl8168d_hw_phy_config(void *ioaddr)
+{
+ struct phy_reg phy_reg_init_0[] = {
+ { 0x1f, 0x0001 },
+ { 0x09, 0x2770 },
+ { 0x08, 0x04d0 },
+ { 0x0b, 0xad15 },
+ { 0x0c, 0x5bf0 },
+ { 0x1c, 0xf101 },
+ { 0x1f, 0x0003 },
+ { 0x14, 0x94d7 },
+ { 0x12, 0xf4d6 },
+ { 0x09, 0xca0f },
+ { 0x1f, 0x0002 },
+ { 0x0b, 0x0b10 },
+ { 0x0c, 0xd1f7 },
+ { 0x1f, 0x0002 },
+ { 0x06, 0x5461 },
+ { 0x1f, 0x0002 },
+ { 0x05, 0x6662 },
+ { 0x1f, 0x0000 },
+ { 0x14, 0x0060 },
+ { 0x1f, 0x0000 },
+ { 0x0d, 0xf8a0 },
+ { 0x1f, 0x0005 },
+ { 0x05, 0xffc2 }
+ };
+
+ DBGP ( "rtl8168d_hw_phy_config\n" );
+
+ rtl_phy_write(ioaddr, phy_reg_init_0, ARRAY_SIZE(phy_reg_init_0));
+
+ if (mdio_read(ioaddr, 0x06) == 0xc400) {
+ struct phy_reg phy_reg_init_1[] = {
+ { 0x1f, 0x0005 },
+ { 0x01, 0x0300 },
+ { 0x1f, 0x0000 },
+ { 0x11, 0x401c },
+ { 0x16, 0x4100 },
+ { 0x1f, 0x0005 },
+ { 0x07, 0x0010 },
+ { 0x05, 0x83dc },
+ { 0x06, 0x087d },
+ { 0x05, 0x8300 },
+ { 0x06, 0x0101 },
+ { 0x06, 0x05f8 },
+ { 0x06, 0xf9fa },
+ { 0x06, 0xfbef },
+ { 0x06, 0x79e2 },
+ { 0x06, 0x835f },
+ { 0x06, 0xe0f8 },
+ { 0x06, 0x9ae1 },
+ { 0x06, 0xf89b },
+ { 0x06, 0xef31 },
+ { 0x06, 0x3b65 },
+ { 0x06, 0xaa07 },
+ { 0x06, 0x81e4 },
+ { 0x06, 0xf89a },
+ { 0x06, 0xe5f8 },
+ { 0x06, 0x9baf },
+ { 0x06, 0x06ae },
+ { 0x05, 0x83dc },
+ { 0x06, 0x8300 },
+ };
+
+ rtl_phy_write(ioaddr, phy_reg_init_1,
+ ARRAY_SIZE(phy_reg_init_1));
+ }
+
+ mdio_write(ioaddr, 0x1f, 0x0000);
+}
+
+static void rtl8102e_hw_phy_config(void *ioaddr)
+{
+ struct phy_reg phy_reg_init[] = {
+ { 0x1f, 0x0003 },
+ { 0x08, 0x441d },
+ { 0x01, 0x9100 },
+ { 0x1f, 0x0000 }
+ };
+
+ DBGP ( "rtl8102e_hw_phy_config\n" );
+
+ mdio_write(ioaddr, 0x1f, 0x0000);
+ mdio_patch(ioaddr, 0x11, 1 << 12);
+ mdio_patch(ioaddr, 0x19, 1 << 13);
+
rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
}
-static void rtl8169_hw_phy_config(struct nic *nic __unused)
+static void rtl_hw_phy_config(struct net_device *dev)
{
- struct rtl8169_private *tp = &tpx;
+ struct rtl8169_private *tp = netdev_priv(dev);
void *ioaddr = tp->mmio_addr;
- DBG("rtl8169_hw_phy_config(): card at addr=0x%lx: priv->mac_version=%d, priv->pcfg=%d\n", (unsigned long) ioaddr, tp->mac_version, tp->pcfg);
+
+ DBGP ( "rtl_hw_phy_config\n" );
+
+ DBG ( "mac_version = 0x%02x\n", tp->mac_version );
switch (tp->mac_version) {
case RTL_GIGA_MAC_VER_01:
@@ -1297,22 +772,1506 @@ static void rtl8169_hw_phy_config(struct nic *nic __unused)
case RTL_GIGA_MAC_VER_04:
rtl8169sb_hw_phy_config(ioaddr);
break;
+ case RTL_GIGA_MAC_VER_07:
+ case RTL_GIGA_MAC_VER_08:
+ case RTL_GIGA_MAC_VER_09:
+ rtl8102e_hw_phy_config(ioaddr);
+ break;
+ case RTL_GIGA_MAC_VER_11:
+ rtl8168bb_hw_phy_config(ioaddr);
+ break;
+ case RTL_GIGA_MAC_VER_12:
+ rtl8168bef_hw_phy_config(ioaddr);
+ break;
+ case RTL_GIGA_MAC_VER_17:
+ rtl8168bef_hw_phy_config(ioaddr);
+ break;
case RTL_GIGA_MAC_VER_18:
- rtl8168cp_hw_phy_config(ioaddr);
+ rtl8168cp_1_hw_phy_config(ioaddr);
break;
case RTL_GIGA_MAC_VER_19:
- rtl8168c_hw_phy_config(ioaddr);
+ rtl8168c_1_hw_phy_config(ioaddr);
break;
case RTL_GIGA_MAC_VER_20:
- rtl8168cx_hw_phy_config(ioaddr);
+ rtl8168c_2_hw_phy_config(ioaddr);
+ break;
+ case RTL_GIGA_MAC_VER_21:
+ rtl8168c_3_hw_phy_config(ioaddr);
+ break;
+ case RTL_GIGA_MAC_VER_22:
+ rtl8168c_4_hw_phy_config(ioaddr);
break;
+ case RTL_GIGA_MAC_VER_23:
+ case RTL_GIGA_MAC_VER_24:
+ rtl8168cp_2_hw_phy_config(ioaddr);
+ break;
+ case RTL_GIGA_MAC_VER_25:
+ rtl8168d_hw_phy_config(ioaddr);
+ break;
+
+ default:
+ break;
+ }
+}
+
+static void rtl8169_phy_reset(struct net_device *dev __unused,
+ struct rtl8169_private *tp)
+{
+ void *ioaddr = tp->mmio_addr;
+ unsigned int i;
+
+ DBGP ( "rtl8169_phy_reset\n" );
+
+ tp->phy_reset_enable(ioaddr);
+ for (i = 0; i < 100; i++) {
+ if (!tp->phy_reset_pending(ioaddr))
+ return;
+ mdelay ( 1 );
+ }
+ DBG ( "PHY reset failed.\n" );
+}
+
+static void rtl8169_init_phy(struct net_device *dev, struct rtl8169_private *tp)
+{
+ void *ioaddr = tp->mmio_addr;
+
+ DBGP ( "rtl8169_init_phy\n" );
+
+ rtl_hw_phy_config(dev);
+
+ if (tp->mac_version <= RTL_GIGA_MAC_VER_06) {
+ DBG ( "Set MAC Reg C+CR Offset 0x82h = 0x01h\n" );
+ RTL_W8(0x82, 0x01);
+ }
+
+ pci_write_config_byte(tp->pci_dev, PCI_LATENCY_TIMER, 0x40);
+
+ if (tp->mac_version <= RTL_GIGA_MAC_VER_06)
+ pci_write_config_byte(tp->pci_dev, PCI_CACHE_LINE_SIZE, 0x08);
+
+ if (tp->mac_version == RTL_GIGA_MAC_VER_02) {
+ DBG ( "Set MAC Reg C+CR Offset 0x82h = 0x01h\n" );
+ RTL_W8(0x82, 0x01);
+ DBG ( "Set PHY Reg 0x0bh = 0x00h\n" );
+ mdio_write(ioaddr, 0x0b, 0x0000); //w 0x0b 15 0 0
+ }
+
+ rtl8169_phy_reset(dev, tp);
+
+ /*
+ * rtl8169_set_speed_xmii takes good care of the Fast Ethernet
+ * only 8101. Don't panic.
+ */
+ rtl8169_set_speed(dev, AUTONEG_ENABLE, SPEED_1000, DUPLEX_FULL);
+
+ if ((RTL_R8(PHYstatus) & TBI_Enable))
+ DBG ( "TBI auto-negotiating\n" );
+}
+
+static const struct rtl_cfg_info {
+ void (*hw_start)(struct net_device *);
+ unsigned int region;
+ unsigned int align;
+ u16 intr_event;
+ u16 napi_event;
+ unsigned features;
+} rtl_cfg_infos [] = {
+ [RTL_CFG_0] = {
+ .hw_start = rtl_hw_start_8169,
+ .region = 1,
+ .align = 0,
+ .intr_event = SYSErr | LinkChg | RxOverflow |
+ RxFIFOOver | TxErr | TxOK | RxOK | RxErr,
+ .napi_event = RxFIFOOver | TxErr | TxOK | RxOK | RxOverflow,
+ .features = RTL_FEATURE_GMII
+ },
+ [RTL_CFG_1] = {
+ .hw_start = rtl_hw_start_8168,
+ .region = 2,
+ .align = 8,
+ .intr_event = SYSErr | LinkChg | RxOverflow |
+ TxErr | TxOK | RxOK | RxErr,
+ .napi_event = TxErr | TxOK | RxOK | RxOverflow,
+ .features = RTL_FEATURE_GMII
+ },
+ [RTL_CFG_2] = {
+ .hw_start = rtl_hw_start_8101,
+ .region = 2,
+ .align = 8,
+ .intr_event = SYSErr | LinkChg | RxOverflow | PCSTimeout |
+ RxFIFOOver | TxErr | TxOK | RxOK | RxErr,
+ .napi_event = RxFIFOOver | TxErr | TxOK | RxOK | RxOverflow,
+ }
+};
+
+static void rtl8169_hw_reset(void *ioaddr)
+{
+ DBGP ( "rtl8169_hw_reset\n" );
+
+ /* Disable interrupts */
+ rtl8169_irq_mask_and_ack(ioaddr);
+
+ /* Reset the chipset */
+ RTL_W8(ChipCmd, CmdReset);
+
+ /* PCI commit */
+ RTL_R8(ChipCmd);
+}
+
+static void rtl_set_rx_tx_config_registers(struct rtl8169_private *tp)
+{
+ void *ioaddr = tp->mmio_addr;
+ u32 cfg = rtl8169_rx_config;
+
+ DBGP ( "rtl_set_rx_tx_config_registers\n" );
+
+ cfg |= (RTL_R32(RxConfig) & rtl_chip_info[tp->chipset].RxConfigMask);
+ RTL_W32(RxConfig, cfg);
+
+ /* Set DMA burst size and Interframe Gap Time */
+ RTL_W32(TxConfig, (TX_DMA_BURST << TxDMAShift) |
+ (InterFrameGap << TxInterFrameGapShift));
+}
+
+static void rtl_soft_reset ( struct net_device *dev )
+{
+ struct rtl8169_private *tp = netdev_priv(dev);
+ void *ioaddr = tp->mmio_addr;
+ unsigned int i;
+
+ DBGP ( "rtl_hw_soft_reset\n" );
+
+ /* Soft reset the chip. */
+ RTL_W8(ChipCmd, CmdReset);
+
+ /* Check that the chip has finished the reset. */
+ for (i = 0; i < 100; i++) {
+ if ((RTL_R8(ChipCmd) & CmdReset) == 0)
+ break;
+ mdelay ( 1 );
+ }
+
+ if ( i == 100 ) {
+ DBG ( "Reset Failed! (> 100 iterations)\n" );
+ }
+}
+
+static void rtl_hw_start ( struct net_device *dev )
+{
+ struct rtl8169_private *tp = netdev_priv ( dev );
+
+ DBGP ( "rtl_hw_start\n" );
+
+ /* Soft reset NIC */
+ rtl_soft_reset ( dev );
+
+ tp->hw_start ( dev );
+}
+
+static void rtl_set_rx_tx_desc_registers(struct rtl8169_private *tp,
+ void *ioaddr)
+{
+ DBGP ( "rtl_set_rx_tx_desc_registers\n" );
+
+ /*
+ * Magic spell: some iop3xx ARM board needs the TxDescAddrHigh
+ * register to be written before TxDescAddrLow to work.
+ * Switching from MMIO to I/O access fixes the issue as well.
+ */
+ RTL_W32 ( TxDescStartAddrHigh, 0 );
+ RTL_W32 ( TxDescStartAddrLow, virt_to_bus ( tp->tx_base ) );
+ RTL_W32 ( RxDescAddrHigh, 0 );
+ RTL_W32 ( RxDescAddrLow, virt_to_bus ( tp->rx_base ) );
+}
+
+static u16 rtl_rw_cpluscmd(void *ioaddr)
+{
+ u16 cmd;
+
+ DBGP ( "rtl_rw_cpluscmd\n" );
+
+ cmd = RTL_R16(CPlusCmd);
+ RTL_W16(CPlusCmd, cmd);
+ return cmd;
+}
+
+static void rtl_set_rx_max_size(void *ioaddr)
+{
+ DBGP ( "rtl_set_rx_max_size\n" );
+
+ RTL_W16 ( RxMaxSize, RX_BUF_SIZE );
+}
+
+static void rtl8169_set_magic_reg(void *ioaddr, unsigned mac_version)
+{
+ struct {
+ u32 mac_version;
+ u32 clk;
+ u32 val;
+ } cfg2_info [] = {
+ { RTL_GIGA_MAC_VER_05, PCI_Clock_33MHz, 0x000fff00 }, // 8110SCd
+ { RTL_GIGA_MAC_VER_05, PCI_Clock_66MHz, 0x000fffff },
+ { RTL_GIGA_MAC_VER_06, PCI_Clock_33MHz, 0x00ffff00 }, // 8110SCe
+ { RTL_GIGA_MAC_VER_06, PCI_Clock_66MHz, 0x00ffffff }
+ }, *p = cfg2_info;
+ unsigned int i;
+ u32 clk;
+
+ DBGP ( "rtl8169_set_magic_reg\n" );
+
+ clk = RTL_R8(Config2) & PCI_Clock_66MHz;
+ for (i = 0; i < ARRAY_SIZE(cfg2_info); i++, p++) {
+ if ((p->mac_version == mac_version) && (p->clk == clk)) {
+ RTL_W32(0x7c, p->val);
+ break;
+ }
+ }
+}
+
+static void rtl_set_rx_mode ( struct net_device *netdev )
+{
+ struct rtl8169_private *tp = netdev_priv ( netdev );
+ void *ioaddr = tp->mmio_addr;
+ u32 tmp;
+
+ DBGP ( "rtl_set_rx_mode\n" );
+
+ /* Accept all Multicast Packets */
+
+ RTL_W32 ( MAR0 + 0, 0xffffffff );
+ RTL_W32 ( MAR0 + 4, 0xffffffff );
+
+ tmp = rtl8169_rx_config | AcceptBroadcast | AcceptMulticast | AcceptMyPhys |
+ ( RTL_R32 ( RxConfig ) & rtl_chip_info[tp->chipset].RxConfigMask );
+
+ RTL_W32 ( RxConfig, tmp );
+}
+
+static void rtl_hw_start_8169(struct net_device *dev)
+{
+ struct rtl8169_private *tp = netdev_priv(dev);
+ void *ioaddr = tp->mmio_addr;
+ struct pci_device *pdev = tp->pci_dev;
+
+ DBGP ( "rtl_hw_start_8169\n" );
+
+ if (tp->mac_version == RTL_GIGA_MAC_VER_05) {
+ RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) | PCIMulRW);
+ pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 0x08);
+ }
+
+ RTL_W8(Cfg9346, Cfg9346_Unlock);
+
+ if ((tp->mac_version == RTL_GIGA_MAC_VER_01) ||
+ (tp->mac_version == RTL_GIGA_MAC_VER_02) ||
+ (tp->mac_version == RTL_GIGA_MAC_VER_03) ||
+ (tp->mac_version == RTL_GIGA_MAC_VER_04))
+ RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
+
+ RTL_W8(EarlyTxThres, EarlyTxThld);
+
+ rtl_set_rx_max_size(ioaddr);
+
+ if ((tp->mac_version == RTL_GIGA_MAC_VER_01) ||
+ (tp->mac_version == RTL_GIGA_MAC_VER_02) ||
+ (tp->mac_version == RTL_GIGA_MAC_VER_03) ||
+ (tp->mac_version == RTL_GIGA_MAC_VER_04))
+ rtl_set_rx_tx_config_registers(tp);
+
+ tp->cp_cmd |= rtl_rw_cpluscmd(ioaddr) | PCIMulRW;
+
+ if ((tp->mac_version == RTL_GIGA_MAC_VER_02) ||
+ (tp->mac_version == RTL_GIGA_MAC_VER_03)) {
+ DBG ( "Set MAC Reg C+CR Offset 0xE0. "
+ "Bit-3 and bit-14 MUST be 1\n" );
+ tp->cp_cmd |= (1 << 14);
+ }
+
+ RTL_W16(CPlusCmd, tp->cp_cmd);
+
+ rtl8169_set_magic_reg(ioaddr, tp->mac_version);
+
+ /*
+ * Undocumented corner. Supposedly:
+ * (TxTimer << 12) | (TxPackets << 8) | (RxTimer << 4) | RxPackets
+ */
+ RTL_W16(IntrMitigate, 0x0000);
+
+ rtl_set_rx_tx_desc_registers(tp, ioaddr);
+
+ if ((tp->mac_version != RTL_GIGA_MAC_VER_01) &&
+ (tp->mac_version != RTL_GIGA_MAC_VER_02) &&
+ (tp->mac_version != RTL_GIGA_MAC_VER_03) &&
+ (tp->mac_version != RTL_GIGA_MAC_VER_04)) {
+ RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
+ rtl_set_rx_tx_config_registers(tp);
+ }
+
+ RTL_W8(Cfg9346, Cfg9346_Lock);
+
+ /* Initially a 10 us delay. Turned it into a PCI commit. - FR */
+ RTL_R8(IntrMask);
+
+ RTL_W32(RxMissed, 0);
+
+ rtl_set_rx_mode(dev);
+
+ /* no early-rx interrupts */
+ RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xF000);
+
+ // RTL_W16(IntrMask, tp->intr_event);
+}
+
+static void rtl_tx_performance_tweak(struct pci_device *pdev, u16 force)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+ struct rtl8169_private *tp = netdev_priv(dev);
+ int cap = tp->pcie_cap;
+
+ DBGP ( "rtl_tx_performance_tweak\n" );
+
+ if (cap) {
+ u16 ctl;
+
+ pci_read_config_word(pdev, cap + PCI_EXP_DEVCTL, &ctl);
+ ctl = (ctl & ~PCI_EXP_DEVCTL_READRQ) | force;
+ pci_write_config_word(pdev, cap + PCI_EXP_DEVCTL, ctl);
+ }
+}
+
+static void rtl_csi_access_enable(void *ioaddr)
+{
+ u32 csi;
+
+ DBGP ( "rtl_csi_access_enable\n" );
+
+ csi = rtl_csi_read(ioaddr, 0x070c) & 0x00ffffff;
+ rtl_csi_write(ioaddr, 0x070c, csi | 0x27000000);
+}
+
+struct ephy_info {
+ unsigned int offset;
+ u16 mask;
+ u16 bits;
+};
+
+static void rtl_ephy_init(void *ioaddr, struct ephy_info *e, int len)
+{
+ u16 w;
+
+ DBGP ( "rtl_ephy_init\n" );
+
+ while (len-- > 0) {
+ w = (rtl_ephy_read(ioaddr, e->offset) & ~e->mask) | e->bits;
+ rtl_ephy_write(ioaddr, e->offset, w);
+ e++;
+ }
+}
+
+static void rtl_disable_clock_request(struct pci_device *pdev)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+ struct rtl8169_private *tp = netdev_priv(dev);
+ int cap = tp->pcie_cap;
+
+ DBGP ( "rtl_disable_clock_request\n" );
+
+ if (cap) {
+ u16 ctl;
+
+ pci_read_config_word(pdev, cap + PCI_EXP_LNKCTL, &ctl);
+ ctl &= ~PCI_EXP_LNKCTL_CLKREQ_EN;
+ pci_write_config_word(pdev, cap + PCI_EXP_LNKCTL, ctl);
+ }
+}
+
+#define R8168_CPCMD_QUIRK_MASK (\
+ EnableBist | \
+ Mac_dbgo_oe | \
+ Force_half_dup | \
+ Force_rxflow_en | \
+ Force_txflow_en | \
+ Cxpl_dbg_sel | \
+ ASF | \
+ PktCntrDisable | \
+ Mac_dbgo_sel)
+
+static void rtl_hw_start_8168bb(void *ioaddr, struct pci_device *pdev)
+{
+ DBGP ( "rtl_hw_start_8168bb\n" );
+
+ RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
+
+ RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK);
+
+ rtl_tx_performance_tweak(pdev,
+ (0x5 << MAX_READ_REQUEST_SHIFT) | PCI_EXP_DEVCTL_NOSNOOP_EN);
+}
+
+static void rtl_hw_start_8168bef(void *ioaddr, struct pci_device *pdev)
+{
+ DBGP ( "rtl_hw_start_8168bef\n" );
+
+ rtl_hw_start_8168bb(ioaddr, pdev);
+
+ RTL_W8(EarlyTxThres, EarlyTxThld);
+
+ RTL_W8(Config4, RTL_R8(Config4) & ~(1 << 0));
+}
+
+static void __rtl_hw_start_8168cp(void *ioaddr, struct pci_device *pdev)
+{
+ DBGP ( "__rtl_hw_start_8168cp\n" );
+
+ RTL_W8(Config1, RTL_R8(Config1) | Speed_down);
+
+ RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
+
+ rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
+
+ rtl_disable_clock_request(pdev);
+
+ RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK);
+}
+
+static void rtl_hw_start_8168cp_1(void *ioaddr, struct pci_device *pdev)
+{
+ static struct ephy_info e_info_8168cp[] = {
+ { 0x01, 0, 0x0001 },
+ { 0x02, 0x0800, 0x1000 },
+ { 0x03, 0, 0x0042 },
+ { 0x06, 0x0080, 0x0000 },
+ { 0x07, 0, 0x2000 }
+ };
+
+ DBGP ( "rtl_hw_start_8168cp_1\n" );
+
+ rtl_csi_access_enable(ioaddr);
+
+ rtl_ephy_init(ioaddr, e_info_8168cp, ARRAY_SIZE(e_info_8168cp));
+
+ __rtl_hw_start_8168cp(ioaddr, pdev);
+}
+
+static void rtl_hw_start_8168cp_2(void *ioaddr, struct pci_device *pdev)
+{
+ DBGP ( "rtl_hw_start_8168cp_2\n" );
+
+ rtl_csi_access_enable(ioaddr);
+
+ RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
+
+ rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
+
+ RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK);
+}
+
+static void rtl_hw_start_8168cp_3(void *ioaddr, struct pci_device *pdev)
+{
+ DBGP ( "rtl_hw_start_8168cp_3\n" );
+
+ rtl_csi_access_enable(ioaddr);
+
+ RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
+
+ /* Magic. */
+ RTL_W8(DBG_REG, 0x20);
+
+ RTL_W8(EarlyTxThres, EarlyTxThld);
+
+ rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
+
+ RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK);
+}
+
+static void rtl_hw_start_8168c_1(void *ioaddr, struct pci_device *pdev)
+{
+ static struct ephy_info e_info_8168c_1[] = {
+ { 0x02, 0x0800, 0x1000 },
+ { 0x03, 0, 0x0002 },
+ { 0x06, 0x0080, 0x0000 }
+ };
+
+ DBGP ( "rtl_hw_start_8168c_1\n" );
+
+ rtl_csi_access_enable(ioaddr);
+
+ RTL_W8(DBG_REG, 0x06 | FIX_NAK_1 | FIX_NAK_2);
+
+ rtl_ephy_init(ioaddr, e_info_8168c_1, ARRAY_SIZE(e_info_8168c_1));
+
+ __rtl_hw_start_8168cp(ioaddr, pdev);
+}
+
+static void rtl_hw_start_8168c_2(void *ioaddr, struct pci_device *pdev)
+{
+ static struct ephy_info e_info_8168c_2[] = {
+ { 0x01, 0, 0x0001 },
+ { 0x03, 0x0400, 0x0220 }
+ };
+
+ DBGP ( "rtl_hw_start_8168c_2\n" );
+
+ rtl_csi_access_enable(ioaddr);
+
+ rtl_ephy_init(ioaddr, e_info_8168c_2, ARRAY_SIZE(e_info_8168c_2));
+
+ __rtl_hw_start_8168cp(ioaddr, pdev);
+}
+
+static void rtl_hw_start_8168c_3(void *ioaddr, struct pci_device *pdev)
+{
+ DBGP ( "rtl_hw_start_8168c_3\n" );
+
+ rtl_hw_start_8168c_2(ioaddr, pdev);
+}
+
+static void rtl_hw_start_8168c_4(void *ioaddr, struct pci_device *pdev)
+{
+ DBGP ( "rtl_hw_start_8168c_4\n" );
+
+ rtl_csi_access_enable(ioaddr);
+
+ __rtl_hw_start_8168cp(ioaddr, pdev);
+}
+
+static void rtl_hw_start_8168d(void *ioaddr, struct pci_device *pdev)
+{
+ DBGP ( "rtl_hw_start_8168d\n" );
+
+ rtl_csi_access_enable(ioaddr);
+
+ rtl_disable_clock_request(pdev);
+
+ RTL_W8(EarlyTxThres, EarlyTxThld);
+
+ rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
+
+ RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK);
+}
+
+static void rtl_hw_start_8168(struct net_device *dev)
+{
+ struct rtl8169_private *tp = netdev_priv(dev);
+ void *ioaddr = tp->mmio_addr;
+ struct pci_device *pdev = tp->pci_dev;
+
+ DBGP ( "rtl_hw_start_8168\n" );
+
+ RTL_W8(Cfg9346, Cfg9346_Unlock);
+
+ RTL_W8(EarlyTxThres, EarlyTxThld);
+
+ rtl_set_rx_max_size(ioaddr);
+
+ tp->cp_cmd |= RTL_R16(CPlusCmd) | PktCntrDisable | INTT_1;
+
+ RTL_W16(CPlusCmd, tp->cp_cmd);
+
+ RTL_W16(IntrMitigate, 0x5151);
+
+ /* Work around for RxFIFO overflow. */
+ if (tp->mac_version == RTL_GIGA_MAC_VER_11) {
+ tp->intr_event |= RxFIFOOver | PCSTimeout;
+ tp->intr_event &= ~RxOverflow;
+ }
+
+ rtl_set_rx_tx_desc_registers(tp, ioaddr);
+
+ rtl_set_rx_mode(dev);
+
+ RTL_W32(TxConfig, (TX_DMA_BURST << TxDMAShift) |
+ (InterFrameGap << TxInterFrameGapShift));
+
+ RTL_R8(IntrMask);
+
+ switch (tp->mac_version) {
+ case RTL_GIGA_MAC_VER_11:
+ rtl_hw_start_8168bb(ioaddr, pdev);
+ break;
+
+ case RTL_GIGA_MAC_VER_12:
+ case RTL_GIGA_MAC_VER_17:
+ rtl_hw_start_8168bef(ioaddr, pdev);
+ break;
+
+ case RTL_GIGA_MAC_VER_18:
+ rtl_hw_start_8168cp_1(ioaddr, pdev);
+ break;
+
+ case RTL_GIGA_MAC_VER_19:
+ rtl_hw_start_8168c_1(ioaddr, pdev);
+ break;
+
+ case RTL_GIGA_MAC_VER_20:
+ rtl_hw_start_8168c_2(ioaddr, pdev);
+ break;
+
+ case RTL_GIGA_MAC_VER_21:
+ rtl_hw_start_8168c_3(ioaddr, pdev);
+ break;
+
+ case RTL_GIGA_MAC_VER_22:
+ rtl_hw_start_8168c_4(ioaddr, pdev);
+ break;
+
+ case RTL_GIGA_MAC_VER_23:
+ rtl_hw_start_8168cp_2(ioaddr, pdev);
+ break;
+
+ case RTL_GIGA_MAC_VER_24:
+ rtl_hw_start_8168cp_3(ioaddr, pdev);
+ break;
+
+ case RTL_GIGA_MAC_VER_25:
+ rtl_hw_start_8168d(ioaddr, pdev);
+ break;
+
default:
+ DBG ( "Unknown chipset (mac_version = %d).\n",
+ tp->mac_version );
+ break;
+ }
+
+ RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
+
+ RTL_W8(Cfg9346, Cfg9346_Lock);
+
+ RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xF000);
+
+ // RTL_W16(IntrMask, tp->intr_event);
+}
+
+#define R810X_CPCMD_QUIRK_MASK (\
+ EnableBist | \
+ Mac_dbgo_oe | \
+ Force_half_dup | \
+ Force_half_dup | \
+ Force_txflow_en | \
+ Cxpl_dbg_sel | \
+ ASF | \
+ PktCntrDisable | \
+ PCIDAC | \
+ PCIMulRW)
+
+static void rtl_hw_start_8102e_1(void *ioaddr, struct pci_device *pdev)
+{
+ static struct ephy_info e_info_8102e_1[] = {
+ { 0x01, 0, 0x6e65 },
+ { 0x02, 0, 0x091f },
+ { 0x03, 0, 0xc2f9 },
+ { 0x06, 0, 0xafb5 },
+ { 0x07, 0, 0x0e00 },
+ { 0x19, 0, 0xec80 },
+ { 0x01, 0, 0x2e65 },
+ { 0x01, 0, 0x6e65 }
+ };
+ u8 cfg1;
+
+ DBGP ( "rtl_hw_start_8102e_1\n" );
+
+ rtl_csi_access_enable(ioaddr);
+
+ RTL_W8(DBG_REG, FIX_NAK_1);
+
+ rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
+
+ RTL_W8(Config1,
+ LEDS1 | LEDS0 | Speed_down | MEMMAP | IOMAP | VPD | PMEnable);
+ RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
+
+ cfg1 = RTL_R8(Config1);
+ if ((cfg1 & LEDS0) && (cfg1 & LEDS1))
+ RTL_W8(Config1, cfg1 & ~LEDS0);
+
+ RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R810X_CPCMD_QUIRK_MASK);
+
+ rtl_ephy_init(ioaddr, e_info_8102e_1, ARRAY_SIZE(e_info_8102e_1));
+}
+
+static void rtl_hw_start_8102e_2(void *ioaddr, struct pci_device *pdev)
+{
+ DBGP ( "rtl_hw_start_8102e_2\n" );
+
+ rtl_csi_access_enable(ioaddr);
+
+ rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
+
+ RTL_W8(Config1, MEMMAP | IOMAP | VPD | PMEnable);
+ RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
+
+ RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R810X_CPCMD_QUIRK_MASK);
+}
+
+static void rtl_hw_start_8102e_3(void *ioaddr, struct pci_device *pdev)
+{
+ DBGP ( "rtl_hw_start_8102e_3\n" );
+
+ rtl_hw_start_8102e_2(ioaddr, pdev);
+
+ rtl_ephy_write(ioaddr, 0x03, 0xc2f9);
+}
+
+static void rtl_hw_start_8101(struct net_device *dev)
+{
+ struct rtl8169_private *tp = netdev_priv(dev);
+ void *ioaddr = tp->mmio_addr;
+ struct pci_device *pdev = tp->pci_dev;
+
+ DBGP ( "rtl_hw_start_8101\n" );
+
+ if ((tp->mac_version == RTL_GIGA_MAC_VER_13) ||
+ (tp->mac_version == RTL_GIGA_MAC_VER_16)) {
+ int cap = tp->pcie_cap;
+
+ if (cap) {
+ pci_write_config_word(pdev, cap + PCI_EXP_DEVCTL,
+ PCI_EXP_DEVCTL_NOSNOOP_EN);
+ }
+ }
+
+ switch (tp->mac_version) {
+ case RTL_GIGA_MAC_VER_07:
+ rtl_hw_start_8102e_1(ioaddr, pdev);
+ break;
+
+ case RTL_GIGA_MAC_VER_08:
+ rtl_hw_start_8102e_3(ioaddr, pdev);
+ break;
+
+ case RTL_GIGA_MAC_VER_09:
+ rtl_hw_start_8102e_2(ioaddr, pdev);
+ break;
+ }
+
+ RTL_W8(Cfg9346, Cfg9346_Unlock);
+
+ RTL_W8(EarlyTxThres, EarlyTxThld);
+
+ rtl_set_rx_max_size(ioaddr);
+
+ tp->cp_cmd |= rtl_rw_cpluscmd(ioaddr) | PCIMulRW;
+
+ RTL_W16(CPlusCmd, tp->cp_cmd);
+
+ RTL_W16(IntrMitigate, 0x0000);
+
+ rtl_set_rx_tx_desc_registers(tp, ioaddr);
+
+ RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
+ rtl_set_rx_tx_config_registers(tp);
+
+ RTL_W8(Cfg9346, Cfg9346_Lock);
+
+ RTL_R8(IntrMask);
+
+ rtl_set_rx_mode(dev);
+
+ RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
+
+ RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xf000);
+
+ // RTL_W16(IntrMask, tp->intr_event);
+}
+
+/*** gPXE API Support Routines ***/
+
+/**
+ * setup_tx_resources - allocate tx resources (descriptors)
+ *
+ * @v tp Driver private storage
+ *
+ * @ret rc Returns 0 on success, negative on failure
+ **/
+static int
+rtl8169_setup_tx_resources ( struct rtl8169_private *tp )
+{
+ DBGP ( "rtl8169_setup_tx_resources\n" );
+
+ tp->tx_base = malloc_dma ( R8169_TX_RING_BYTES, TX_RING_ALIGN );
+
+ if ( ! tp->tx_base ) {
+ return -ENOMEM;
+ }
+
+ memset ( tp->tx_base, 0, R8169_TX_RING_BYTES );
+
+ DBG ( "tp->tx_base = %#08lx\n", virt_to_bus ( tp->tx_base ) );
+
+ tp->tx_fill_ctr = 0;
+ tp->tx_curr = 0;
+ tp->tx_tail = 0;
+
+ return 0;
+}
+
+static void
+rtl8169_process_tx_packets ( struct net_device *netdev )
+{
+ struct rtl8169_private *tp = netdev_priv ( netdev );
+
+ uint32_t tx_status;
+ struct TxDesc *tx_curr_desc;
+
+ DBGP ( "rtl8169_process_tx_packets\n" );
+
+ while ( tp->tx_tail != tp->tx_curr ) {
+
+ tx_curr_desc = tp->tx_base + tp->tx_tail;
+
+ tx_status = tx_curr_desc->opts1;
+
+ DBG2 ( "Before DescOwn check tx_status: %#08lx\n", tx_status );
+
+ /* if the packet at tx_tail is not owned by hardware it is for us */
+ if ( tx_status & DescOwn )
+ break;
+
+ DBG ( "Transmitted packet.\n" );
+ DBG ( "tp->tx_fill_ctr = %ld\n", tp->tx_fill_ctr );
+ DBG ( "tp->tx_tail = %ld\n", tp->tx_tail );
+ DBG ( "tp->tx_curr = %ld\n", tp->tx_curr );
+ DBG ( "tx_status = %ld\n", tx_status );
+ DBG ( "tx_curr_desc = %#08lx\n", virt_to_bus ( tx_curr_desc ) );
+
+ /* Pass packet to core for processing */
+ netdev_tx_complete ( netdev, tp->tx_iobuf[tp->tx_tail] );
+
+ memset ( tx_curr_desc, 0, sizeof ( *tx_curr_desc ) );
+
+ /* Decrement count of used descriptors */
+ tp->tx_fill_ctr--;
+
+ /* Increment sent packets index */
+ tp->tx_tail = ( tp->tx_tail + 1 ) % NUM_TX_DESC;
+ }
+}
+
+static void
+rtl8169_free_tx_resources ( struct rtl8169_private *tp )
+{
+ DBGP ( "rtl8169_free_tx_resources\n" );
+
+ free_dma ( tp->tx_base, R8169_TX_RING_BYTES );
+}
+
+static void
+rtl8169_populate_rx_descriptor ( struct rtl8169_private *tp, struct RxDesc *rx_desc, uint32_t index )
+{
+ DBGP ( "rtl8169_populate_rx_descriptor\n" );
+
+ DBG ( "Populating rx descriptor %ld\n", index );
+
+ memset ( rx_desc, 0, sizeof ( *rx_desc ) );
+
+ rx_desc->addr_hi = 0;
+ rx_desc->addr_lo = virt_to_bus ( tp->rx_iobuf[index]->data );
+ rx_desc->opts2 = 0;
+ rx_desc->opts1 = ( index == ( NUM_RX_DESC - 1 ) ? RingEnd : 0 ) |
+ RX_BUF_SIZE;
+ rx_desc->opts1 |= DescOwn;
+}
+
+/**
+ * Refill descriptor ring
+ *
+ * @v netdev Net device
+ */
+static void rtl8169_refill_rx_ring ( struct rtl8169_private *tp )
+{
+ struct RxDesc *rx_curr_desc;
+ int i;
+
+ DBGP ( "rtl8169_refill_rx_ring\n" );
+
+ for ( i = 0; i < NUM_RX_DESC; i++ ) {
+
+ rx_curr_desc = ( tp->rx_base ) + i;
+
+ /* Don't touch descriptors owned by the NIC */
+ if ( rx_curr_desc->opts1 & DescOwn )
+ continue;
+
+ /* Don't touch descriptors with iobufs, they still need to be
+ processed by the poll routine */
+ if ( tp->rx_iobuf[tp->rx_curr] != NULL )
+ continue;
+
+ /** If we can't get an iobuf for this descriptor
+ try again later (next poll).
+ */
+ if ( ! ( tp->rx_iobuf[i] = alloc_iob ( RX_BUF_SIZE ) ) ) {
+ DBG ( "Refill rx ring failed!!\n" );
+ break;
+ }
+
+ rtl8169_populate_rx_descriptor ( tp, rx_curr_desc, i );
+ }
+}
+
+/**
+ * setup_rx_resources - allocate Rx resources (Descriptors)
+ *
+ * @v tp: Driver private structure
+ *
+ * @ret rc Returns 0 on success, negative on failure
+ *
+ **/
+static int
+rtl8169_setup_rx_resources ( struct rtl8169_private *tp )
+{
+ DBGP ( "rtl8169_setup_rx_resources\n" );
+
+ tp->rx_base = malloc_dma ( R8169_RX_RING_BYTES, RX_RING_ALIGN );
+
+ DBG ( "tp->rx_base = %#08lx\n", virt_to_bus ( tp->rx_base ) );
+
+ if ( ! tp->rx_base ) {
+ return -ENOMEM;
+ }
+ memset ( tp->rx_base, 0, R8169_RX_RING_BYTES );
+
+ rtl8169_refill_rx_ring ( tp );
+
+ tp->rx_curr = 0;
+
+ return 0;
+}
+
+static void
+rtl8169_process_rx_packets ( struct net_device *netdev )
+{
+ struct rtl8169_private *tp = netdev_priv ( netdev );
+ uint32_t rx_status;
+ uint16_t rx_len;
+ struct RxDesc *rx_curr_desc;
+ int i;
+
+ DBGP ( "rtl8169_process_rx_packets\n" );
+
+ for ( i = 0; i < NUM_RX_DESC; i++ ) {
+
+ rx_curr_desc = tp->rx_base + tp->rx_curr;
+
+ rx_status = rx_curr_desc->opts1;
+
+ DBG2 ( "Before DescOwn check rx_status: %#08lx\n", rx_status );
+
+ /* Hardware still owns the descriptor */
+ if ( rx_status & DescOwn )
+ break;
+
+ /* We own the descriptor, but it has not been refilled yet */
+ if ( tp->rx_iobuf[tp->rx_curr] == NULL )
+ break;
+
+ rx_len = rx_status & 0x3fff;
+
+ DBG ( "Received packet.\n" );
+ DBG ( "tp->rx_curr = %ld\n", tp->rx_curr );
+ DBG ( "rx_len = %d\n", rx_len );
+ DBG ( "rx_status = %#08lx\n", rx_status );
+ DBG ( "rx_curr_desc = %#08lx\n", virt_to_bus ( rx_curr_desc ) );
+
+ if ( rx_status & RxRES ) {
+
+ netdev_rx_err ( netdev, tp->rx_iobuf[tp->rx_curr], -EINVAL );
+
+ DBG ( "rtl8169_poll: Corrupted packet received!\n"
+ " rx_status: %#08lx\n", rx_status );
+
+ } else {
+
+ /* Adjust size of the iobuf to reflect received data */
+ iob_put ( tp->rx_iobuf[tp->rx_curr], rx_len );
+
+ /* Add this packet to the receive queue. */
+ netdev_rx ( netdev, tp->rx_iobuf[tp->rx_curr] );
+ }
+
+ /* Invalidate this iobuf and descriptor */
+ tp->rx_iobuf[tp->rx_curr] = NULL;
+ memset ( rx_curr_desc, 0, sizeof ( *rx_curr_desc ) );
+
+ /* Update pointer to next available rx descriptor */
+ tp->rx_curr = ( tp->rx_curr + 1 ) % NUM_RX_DESC;
+ }
+ rtl8169_refill_rx_ring ( tp );
+}
+
+static void
+rtl8169_free_rx_resources ( struct rtl8169_private *tp )
+{
+ int i;
+
+ DBGP ( "rtl8169_free_rx_resources\n" );
+
+ free_dma ( tp->rx_base, R8169_RX_RING_BYTES );
+
+ for ( i = 0; i < NUM_RX_DESC; i++ ) {
+ free_iob ( tp->rx_iobuf[i] );
+ tp->rx_iobuf[i] = NULL;
+ }
+}
+
+/**
+ FIXME: Because gPXE's pci_device_id structure does not contain a
+ field to contain arbitrary data, we need the following table to
+ associate PCI IDs with nic variants, because a lot of driver
+ routines depend on knowing which kind of variant they are dealing
+ with. --mdc
+ **/
+
+#define _R(VENDOR,DEVICE,INDEX) \
+ { .vendor = VENDOR, .device = DEVICE, .index = INDEX }
+
+static const struct {
+ uint16_t vendor;
+ uint16_t device;
+ int index;
+} nic_variant_table[] = {
+ _R(0x10ec, 0x8129, RTL_CFG_0),
+ _R(0x10ec, 0x8136, RTL_CFG_2),
+ _R(0x10ec, 0x8167, RTL_CFG_0),
+ _R(0x10ec, 0x8168, RTL_CFG_1),
+ _R(0x10ec, 0x8169, RTL_CFG_0),
+ _R(0x1186, 0x4300, RTL_CFG_0),
+ _R(0x1259, 0xc107, RTL_CFG_0),
+ _R(0x16ec, 0x0116, RTL_CFG_0),
+ _R(0x1737, 0x1032, RTL_CFG_0),
+ _R(0x0001, 0x8168, RTL_CFG_2),
+};
+#undef _R
+
+static int
+rtl8169_get_nic_variant ( uint16_t vendor, uint16_t device )
+{
+ u32 i;
+
+ DBGP ( "rtl8169_get_nic_variant\n" );
+
+ for (i = 0; i < ARRAY_SIZE(nic_variant_table); i++) {
+ if ( ( nic_variant_table[i].vendor == vendor ) &&
+ ( nic_variant_table[i].device == device ) ) {
+ return ( nic_variant_table[i].index );
+ }
+ }
+ DBG ( "No matching NIC variant found!\n" );
+ return ( RTL_CFG_0 );
+}
+
+static void rtl8169_irq_enable ( struct rtl8169_private *tp )
+{
+ void *ioaddr = tp->mmio_addr;
+
+ DBGP ( "rtl8169_irq_enable\n" );
+
+ RTL_W16 ( IntrMask, tp->intr_event );
+}
+
+static void rtl8169_irq_disable ( struct rtl8169_private *tp )
+{
+ void *ioaddr = tp->mmio_addr;
+
+ DBGP ( "rtl8169_irq_disable\n" );
+
+ rtl8169_irq_mask_and_ack ( ioaddr );
+}
+
+/*** gPXE Core API Routines ***/
+
+/**
+ * open - Called when a network interface is made active
+ *
+ * @v netdev network interface device structure
+ * @ret rc Return status code, 0 on success, negative value on failure
+ *
+ **/
+static int
+rtl8169_open ( struct net_device *netdev )
+{
+ struct rtl8169_private *tp = netdev_priv ( netdev );
+ void *ioaddr = tp->mmio_addr;
+ int rc;
+
+ DBGP ( "rtl8169_open\n" );
+
+ /* allocate transmit descriptors */
+ rc = rtl8169_setup_tx_resources ( tp );
+ if ( rc ) {
+ DBG ( "Error setting up TX resources!\n" );
+ goto err_setup_tx;
+ }
+
+ /* allocate receive descriptors */
+ rc = rtl8169_setup_rx_resources ( tp );
+ if ( rc ) {
+ DBG ( "Error setting up RX resources!\n" );
+ goto err_setup_rx;
+ }
+
+ rtl_hw_start ( netdev );
+
+ DBG ( "TxDescStartAddrHigh = %#08lx\n", RTL_R32 ( TxDescStartAddrHigh ) );
+ DBG ( "TxDescStartAddrLow = %#08lx\n", RTL_R32 ( TxDescStartAddrLow ) );
+ DBG ( "RxDescAddrHigh = %#08lx\n", RTL_R32 ( RxDescAddrHigh ) );
+ DBG ( "RxDescAddrLow = %#08lx\n", RTL_R32 ( RxDescAddrLow ) );
+
+ return 0;
+
+err_setup_rx:
+ rtl8169_free_tx_resources ( tp );
+err_setup_tx:
+ rtl8169_hw_reset ( ioaddr );
+
+ return rc;
+}
+
+/**
+ * transmit - Transmit a packet
+ *
+ * @v netdev Network device
+ * @v iobuf I/O buffer
+ *
+ * @ret rc Returns 0 on success, negative on failure
+ */
+static int
+rtl8169_transmit ( struct net_device *netdev, struct io_buffer *iobuf )
+{
+ struct rtl8169_private *tp = netdev_priv ( netdev );
+ void *ioaddr = tp->mmio_addr;
+ uint32_t tx_len = iob_len ( iobuf );
+
+ struct TxDesc *tx_curr_desc;
+
+ DBGP ("rtl8169_transmit\n");
+
+ if ( tp->tx_fill_ctr == NUM_TX_DESC ) {
+ DBG ("TX overflow\n");
+ return -ENOBUFS;
+ }
+
+ /**
+ * The rtl8169 family automatically pads short packets to a
+ * minimum size, but if it did not, like some older cards,
+ * we could do:
+ * iob_pad ( iobuf, ETH_ZLEN );
+ */
+
+ /* Save pointer to this iobuf we have been given to transmit so
+ we can pass it to netdev_tx_complete() later */
+ tp->tx_iobuf[tp->tx_curr] = iobuf;
+
+ tx_curr_desc = tp->tx_base + tp->tx_curr;
+
+ DBG ( "tp->tx_fill_ctr = %ld\n", tp->tx_fill_ctr );
+ DBG ( "tp->tx_curr = %ld\n", tp->tx_curr );
+ DBG ( "tx_curr_desc = %#08lx\n", virt_to_bus ( tx_curr_desc ) );
+ DBG ( "iobuf->data = %#08lx\n", virt_to_bus ( iobuf->data ) );
+ DBG ( "tx_len = %ld\n", tx_len );
+
+ /* Configure current descriptor to transmit supplied packet */
+ tx_curr_desc->addr_hi = 0;
+ tx_curr_desc->addr_lo = virt_to_bus ( iobuf->data );
+ tx_curr_desc->opts2 = 0;
+ tx_curr_desc->opts1 = FirstFrag | LastFrag |
+ ( tp->tx_curr == ( NUM_TX_DESC - 1 ) ? RingEnd : 0 ) |
+ tx_len;
+
+ /* Mark descriptor as owned by NIC */
+ tx_curr_desc->opts1 |= DescOwn;
+
+ DBG ( "tx_curr_desc->opts1 = %#08lx\n", tx_curr_desc->opts1 );
+ DBG ( "tx_curr_desc->opts2 = %#08lx\n", tx_curr_desc->opts2 );
+ DBG ( "tx_curr_desc->addr_hi = %#08lx\n", tx_curr_desc->addr_hi );
+ DBG ( "tx_curr_desc->addr_lo = %#08lx\n", tx_curr_desc->addr_lo );
+
+ RTL_W8 ( TxPoll, NPQ ); /* set polling bit */
+
+ /* Point to next free descriptor */
+ tp->tx_curr = ( tp->tx_curr + 1 ) % NUM_TX_DESC;
+
+ /* Increment number of tx descriptors in use */
+ tp->tx_fill_ctr++;
+
+ return 0;
+}
+
+/**
+ * poll - Poll for received packets
+ *
+ * @v netdev Network device
+ */
+static void
+rtl8169_poll ( struct net_device *netdev )
+{
+ struct rtl8169_private *tp = netdev_priv ( netdev );
+ void *ioaddr = tp->mmio_addr;
+
+ uint16_t intr_status;
+ uint16_t intr_mask;
+
+ DBGP ( "rtl8169_poll\n" );
+
+ intr_status = RTL_R16 ( IntrStatus );
+ intr_mask = RTL_R16 ( IntrMask );
+
+ DBG2 ( "rtl8169_poll (before): intr_mask = %#04x intr_status = %#04x\n",
+ intr_mask, intr_status );
+
+ RTL_W16 ( IntrStatus, 0xffff );
+
+ /* hotplug / major error / no more work / shared irq */
+ if ( intr_status == 0xffff )
+ return;
+
+ /* Process transmitted packets */
+ rtl8169_process_tx_packets ( netdev );
+
+ /* Process received packets */
+ rtl8169_process_rx_packets ( netdev );
+}
+
+/**
+ * close - Disable network interface
+ *
+ * @v netdev network interface device structure
+ *
+ **/
+static void
+rtl8169_close ( struct net_device *netdev )
+{
+ struct rtl8169_private *tp = netdev_priv ( netdev );
+ void *ioaddr = tp->mmio_addr;
+
+ DBGP ( "r8169_close\n" );
+
+ rtl8169_hw_reset ( ioaddr );
+
+ rtl8169_free_tx_resources ( tp );
+ rtl8169_free_rx_resources ( tp );
+}
+
+/**
+ * irq - enable or Disable interrupts
+ *
+ * @v netdev network adapter
+ * @v action requested interrupt action
+ *
+ **/
+static void
+rtl8169_irq ( struct net_device *netdev, int action )
+{
+ struct rtl8169_private *tp = netdev_priv ( netdev );
+
+ DBGP ( "rtl8169_irq\n" );
+
+ switch ( action ) {
+ case 0 :
+ rtl8169_irq_disable ( tp );
+ break;
+ default :
+ rtl8169_irq_enable ( tp );
break;
}
}
-DRIVER ( "r8169/PCI", nic_driver, pci_driver, r8169_driver,
- r8169_probe, r8169_disable );
+static struct net_device_operations rtl8169_operations = {
+ .open = rtl8169_open,
+ .transmit = rtl8169_transmit,
+ .poll = rtl8169_poll,
+ .close = rtl8169_close,
+ .irq = rtl8169_irq,
+};
+
+/**
+ * probe - Initial configuration of NIC
+ *
+ * @v pci PCI device
+ * @v id PCI IDs
+ *
+ * @ret rc Return status code
+ **/
+static int
+rtl8169_probe ( struct pci_device *pdev, const struct pci_device_id *ent )
+{
+ int i, rc;
+ struct net_device *netdev;
+ struct rtl8169_private *tp;
+ void *ioaddr;
+
+ /** FIXME: This lookup is necessary because gPXE does not have a "data"
+ element in the structure pci_device_id which can pass an arbitrary
+ piece of data to the driver. It might be useful to add it. Then we
+ could just use ent->data instead of having to look up cfg_index.
+ **/
+ int cfg_index = rtl8169_get_nic_variant ( ent->vendor, ent->device );
+ const struct rtl_cfg_info *cfg = rtl_cfg_infos + cfg_index;
+
+ DBGP ( "rtl8169_probe\n" );
+
+ DBG ( "ent->vendor = %#04x, ent->device = %#04x\n", ent->vendor, ent->device );
+
+ DBG ( "cfg_index = %d\n", cfg_index );
+ DBG ( "cfg->intr_event = %#04x\n", cfg->intr_event );
+
+ rc = -ENOMEM;
+
+ /* Allocate net device ( also allocates memory for netdev->priv
+ and makes netdev-priv point to it )
+ */
+ netdev = alloc_etherdev ( sizeof ( *tp ) );
+
+ if ( ! netdev )
+ goto err_alloc_etherdev;
+
+ /* Associate driver-specific network operations with
+ generic network device layer
+ */
+ netdev_init ( netdev, &rtl8169_operations );
+
+ /* Associate this network device with the given PCI device */
+ pci_set_drvdata ( pdev, netdev );
+ netdev->dev = &pdev->dev;
+
+ /* Initialize driver private storage */
+ tp = netdev_priv ( netdev );
+ memset ( tp, 0, ( sizeof ( *tp ) ) );
+
+ tp->pci_dev = pdev;
+ tp->irqno = pdev->irq;
+ tp->netdev = netdev;
+ tp->cfg_index = cfg_index;
+ tp->intr_event = cfg->intr_event;
+ tp->cp_cmd = PCIMulRW;
+
+ tp->hw_start = cfg->hw_start;
+
+ rc = -EIO;
+
+ adjust_pci_device ( pdev );
+
+ /* ioremap MMIO region */
+ ioaddr = ioremap ( pdev->membase, R8169_REGS_SIZE );
+
+ if ( ! ioaddr ) {
+ DBG ( "cannot remap MMIO\n" );
+ rc = -EIO;
+ goto err_ioremap;
+ }
+
+ tp->mmio_addr = ioaddr;
+
+ tp->pcie_cap = pci_find_capability ( pdev, PCI_CAP_ID_EXP );
+ if ( tp->pcie_cap ) {
+ DBG ( "PCI Express capability\n" );
+ } else {
+ DBG ( "No PCI Express capability\n" );
+ }
+
+ /* Mask interrupts just in case */
+ rtl8169_irq_mask_and_ack ( ioaddr );
+
+ /* Soft reset NIC */
+ rtl_soft_reset ( netdev );
+
+ /* Identify chip attached to board */
+ rtl8169_get_mac_version ( tp, ioaddr );
+
+ for ( i = 0; (u32) i < ARRAY_SIZE ( rtl_chip_info ); i++ ) {
+ if ( tp->mac_version == rtl_chip_info[i].mac_version )
+ break;
+ }
+ if ( i == ARRAY_SIZE(rtl_chip_info ) ) {
+ /* Unknown chip: assume array element #0, original RTL-8169 */
+ DBG ( "Unknown chip version, assuming %s\n", rtl_chip_info[0].name );
+ i = 0;
+ }
+ tp->chipset = i;
+
+ if ((tp->mac_version <= RTL_GIGA_MAC_VER_06) &&
+ (RTL_R8(PHYstatus) & TBI_Enable)) {
+ tp->set_speed = rtl8169_set_speed_tbi;
+ tp->phy_reset_enable = rtl8169_tbi_reset_enable;
+ tp->phy_reset_pending = rtl8169_tbi_reset_pending;
+ tp->link_ok = rtl8169_tbi_link_ok;
+
+ tp->phy_1000_ctrl_reg = ADVERTISE_1000FULL; /* Implied by TBI */
+ } else {
+ tp->set_speed = rtl8169_set_speed_xmii;
+ tp->phy_reset_enable = rtl8169_xmii_reset_enable;
+ tp->phy_reset_pending = rtl8169_xmii_reset_pending;
+ tp->link_ok = rtl8169_xmii_link_ok;
+ }
+
+ /* Get MAC address */
+ for ( i = 0; i < MAC_ADDR_LEN; i++ )
+ netdev->ll_addr[i] = RTL_R8 ( MAC0 + i );
+
+ DBG ( "%s\n", eth_ntoa ( netdev->ll_addr ) );
+
+ rtl8169_init_phy ( netdev, tp );
+
+ if ( ( rc = register_netdev ( netdev ) ) != 0 )
+ goto err_register;
+
+ /* Mark as link up; we don't yet handle link state */
+ netdev_link_up ( netdev );
+
+ DBG ( "rtl8169_probe succeeded!\n" );
+
+ /* No errors, return success */
+ return 0;
+
+/* Error return paths */
+err_register:
+err_ioremap:
+ netdev_put ( netdev );
+err_alloc_etherdev:
+ return rc;
+}
+
+/**
+ * remove - Device Removal Routine
+ *
+ * @v pdev PCI device information struct
+ *
+ **/
+static void
+rtl8169_remove ( struct pci_device *pdev )
+{
+ struct net_device *netdev = pci_get_drvdata ( pdev );
+ struct rtl8169_private *tp = netdev_priv ( netdev );
+ void *ioaddr = tp->mmio_addr;
+
+ DBGP ( "rtl8169_remove\n" );
+
+ rtl8169_hw_reset ( ioaddr );
+
+ unregister_netdev ( netdev );
+ netdev_nullify ( netdev );
+ netdev_put ( netdev );
+}
+
+static struct pci_device_id rtl8169_nics[] = {
+ PCI_ROM(0x10ec, 0x8129, "rtl8169-0x8129", "rtl8169-0x8129"),
+ PCI_ROM(0x10ec, 0x8136, "rtl8169-0x8136", "rtl8169-0x8136"),
+ PCI_ROM(0x10ec, 0x8167, "rtl8169-0x8167", "rtl8169-0x8167"),
+ PCI_ROM(0x10ec, 0x8168, "rtl8169-0x8168", "rtl8169-0x8168"),
+ PCI_ROM(0x10ec, 0x8169, "rtl8169-0x8169", "rtl8169-0x8169"),
+ PCI_ROM(0x1186, 0x4300, "rtl8169-0x4300", "rtl8169-0x4300"),
+ PCI_ROM(0x1259, 0xc107, "rtl8169-0xc107", "rtl8169-0xc107"),
+ PCI_ROM(0x16ec, 0x0116, "rtl8169-0x0116", "rtl8169-0x0116"),
+ PCI_ROM(0x1737, 0x1032, "rtl8169-0x1032", "rtl8169-0x1032"),
+ PCI_ROM(0x0001, 0x8168, "rtl8169-0x8168", "rtl8169-0x8168"),
+};
+
+struct pci_driver rtl8169_driver __pci_driver = {
+ .ids = rtl8169_nics,
+ .id_count = ( sizeof ( rtl8169_nics ) / sizeof ( rtl8169_nics[0] ) ),
+ .probe = rtl8169_probe,
+ .remove = rtl8169_remove,
+};
/*
* Local variables:
diff --git a/gpxe/src/drivers/net/r8169.h b/gpxe/src/drivers/net/r8169.h
new file mode 100644
index 00000000..d3536326
--- /dev/null
+++ b/gpxe/src/drivers/net/r8169.h
@@ -0,0 +1,566 @@
+/*
+ * Copyright (c) 2008 Marty Connor <mdc@etherboot.org>
+ * Copyright (c) 2008 Entity Cyber, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * This driver is based on rtl8169 data sheets and work by:
+ *
+ * Copyright (c) 2002 ShuChen <shuchen@realtek.com.tw>
+ * Copyright (c) 2003 - 2007 Francois Romieu <romieu@fr.zoreil.com>
+ * Copyright (c) a lot of people too. Please respect their work.
+ *
+ */
+
+#ifndef _R8169_H_
+#define _R8169_H_
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+/** FIXME: include/linux/pci_regs.h has these PCI regs, maybe
+ we need such a file in gPXE?
+**/
+#define PCI_EXP_DEVCTL 8 /* Device Control */
+#define PCI_EXP_DEVCTL_READRQ 0x7000 /* Max_Read_Request_Size */
+#define PCI_EXP_LNKCTL 16 /* Link Control */
+#define PCI_EXP_LNKCTL_CLKREQ_EN 0x100 /* Enable clkreq */
+#define PCI_EXP_DEVCTL_NOSNOOP_EN 0x0800 /* Enable No Snoop */
+
+/** FIXME: update mii.h in src/include/mii.h from Linux sources
+ so we don't have to include these definitiions.
+**/
+/* The forced speed, 10Mb, 100Mb, gigabit, 2.5Gb, 10GbE. */
+#define SPEED_10 10
+#define SPEED_100 100
+#define SPEED_1000 1000
+#define SPEED_2500 2500
+#define SPEED_10000 10000
+
+/* Duplex, half or full. */
+#define DUPLEX_HALF 0x00
+#define DUPLEX_FULL 0x01
+
+/* Generic MII registers. */
+
+#define MII_BMCR 0x00 /* Basic mode control register */
+#define MII_BMSR 0x01 /* Basic mode status register */
+#define MII_PHYSID1 0x02 /* PHYS ID 1 */
+#define MII_PHYSID2 0x03 /* PHYS ID 2 */
+#define MII_ADVERTISE 0x04 /* Advertisement control reg */
+#define MII_LPA 0x05 /* Link partner ability reg */
+#define MII_EXPANSION 0x06 /* Expansion register */
+#define MII_CTRL1000 0x09 /* 1000BASE-T control */
+#define MII_STAT1000 0x0a /* 1000BASE-T status */
+#define MII_ESTATUS 0x0f /* Extended Status */
+#define MII_DCOUNTER 0x12 /* Disconnect counter */
+#define MII_FCSCOUNTER 0x13 /* False carrier counter */
+#define MII_NWAYTEST 0x14 /* N-way auto-neg test reg */
+#define MII_RERRCOUNTER 0x15 /* Receive error counter */
+#define MII_SREVISION 0x16 /* Silicon revision */
+#define MII_RESV1 0x17 /* Reserved... */
+#define MII_LBRERROR 0x18 /* Lpback, rx, bypass error */
+#define MII_PHYADDR 0x19 /* PHY address */
+#define MII_RESV2 0x1a /* Reserved... */
+#define MII_TPISTATUS 0x1b /* TPI status for 10mbps */
+#define MII_NCONFIG 0x1c /* Network interface config */
+
+/* Basic mode control register. */
+#define BMCR_RESV 0x003f /* Unused... */
+#define BMCR_SPEED1000 0x0040 /* MSB of Speed (1000) */
+#define BMCR_CTST 0x0080 /* Collision test */
+#define BMCR_FULLDPLX 0x0100 /* Full duplex */
+#define BMCR_ANRESTART 0x0200 /* Auto negotiation restart */
+#define BMCR_ISOLATE 0x0400 /* Disconnect DP83840 from MII */
+#define BMCR_PDOWN 0x0800 /* Powerdown the DP83840 */
+#define BMCR_ANENABLE 0x1000 /* Enable auto negotiation */
+#define BMCR_SPEED100 0x2000 /* Select 100Mbps */
+#define BMCR_LOOPBACK 0x4000 /* TXD loopback bits */
+#define BMCR_RESET 0x8000 /* Reset the DP83840 */
+
+/* Basic mode status register. */
+#define BMSR_ERCAP 0x0001 /* Ext-reg capability */
+#define BMSR_JCD 0x0002 /* Jabber detected */
+#define BMSR_LSTATUS 0x0004 /* Link status */
+#define BMSR_ANEGCAPABLE 0x0008 /* Able to do auto-negotiation */
+#define BMSR_RFAULT 0x0010 /* Remote fault detected */
+#define BMSR_ANEGCOMPLETE 0x0020 /* Auto-negotiation complete */
+#define BMSR_RESV 0x00c0 /* Unused... */
+#define BMSR_ESTATEN 0x0100 /* Extended Status in R15 */
+#define BMSR_100HALF2 0x0200 /* Can do 100BASE-T2 HDX */
+#define BMSR_100FULL2 0x0400 /* Can do 100BASE-T2 FDX */
+#define BMSR_10HALF 0x0800 /* Can do 10mbps, half-duplex */
+#define BMSR_10FULL 0x1000 /* Can do 10mbps, full-duplex */
+#define BMSR_100HALF 0x2000 /* Can do 100mbps, half-duplex */
+#define BMSR_100FULL 0x4000 /* Can do 100mbps, full-duplex */
+#define BMSR_100BASE4 0x8000 /* Can do 100mbps, 4k packets */
+
+#define AUTONEG_DISABLE 0x00
+#define AUTONEG_ENABLE 0x01
+
+#define MII_ADVERTISE 0x04 /* Advertisement control reg */
+#define ADVERTISE_SLCT 0x001f /* Selector bits */
+#define ADVERTISE_CSMA 0x0001 /* Only selector supported */
+#define ADVERTISE_10HALF 0x0020 /* Try for 10mbps half-duplex */
+#define ADVERTISE_1000XFULL 0x0020 /* Try for 1000BASE-X full-duplex */
+#define ADVERTISE_10FULL 0x0040 /* Try for 10mbps full-duplex */
+#define ADVERTISE_1000XHALF 0x0040 /* Try for 1000BASE-X half-duplex */
+#define ADVERTISE_100HALF 0x0080 /* Try for 100mbps half-duplex */
+#define ADVERTISE_1000XPAUSE 0x0080 /* Try for 1000BASE-X pause */
+#define ADVERTISE_100FULL 0x0100 /* Try for 100mbps full-duplex */
+#define ADVERTISE_1000XPSE_ASYM 0x0100 /* Try for 1000BASE-X asym pause */
+#define ADVERTISE_100BASE4 0x0200 /* Try for 100mbps 4k packets */
+#define ADVERTISE_PAUSE_CAP 0x0400 /* Try for pause */
+#define ADVERTISE_PAUSE_ASYM 0x0800 /* Try for asymetric pause */
+#define ADVERTISE_RESV 0x1000 /* Unused... */
+#define ADVERTISE_RFAULT 0x2000 /* Say we can detect faults */
+#define ADVERTISE_LPACK 0x4000 /* Ack link partners response */
+#define ADVERTISE_NPAGE 0x8000 /* Next page bit */
+#define ADVERTISE_FULL (ADVERTISE_100FULL | ADVERTISE_10FULL | \
+ ADVERTISE_CSMA)
+#define ADVERTISE_ALL (ADVERTISE_10HALF | ADVERTISE_10FULL | \
+ ADVERTISE_100HALF | ADVERTISE_100FULL)
+
+/* 1000BASE-T Control register */
+#define ADVERTISE_1000FULL 0x0200 /* Advertise 1000BASE-T full duplex */
+#define ADVERTISE_1000HALF 0x0100 /* Advertise 1000BASE-T half duplex */
+
+/* MAC address length */
+#define MAC_ADDR_LEN 6
+
+#define MAX_READ_REQUEST_SHIFT 12
+#define RX_FIFO_THRESH 7 /* 7 means NO threshold, Rx buffer level before first PCI xfer. */
+#define RX_DMA_BURST 6 /* Maximum PCI burst, '6' is 1024 */
+#define TX_DMA_BURST 6 /* Maximum PCI burst, '6' is 1024 */
+#define EarlyTxThld 0x3F /* 0x3F means NO early transmit */
+#define RxPacketMaxSize 0x3FE8 /* 16K - 1 - ETH_HLEN - VLAN - CRC... */
+#define SafeMtu 0x1c20 /* ... actually life sucks beyond ~7k */
+#define InterFrameGap 0x03 /* 3 means InterFrameGap = the shortest one */
+
+#define R8169_REGS_SIZE 256
+#define R8169_NAPI_WEIGHT 64
+#define NUM_TX_DESC 8 /* Number of Tx descriptor registers */
+#define NUM_RX_DESC 8 /* Number of Rx descriptor registers */
+#define RX_BUF_SIZE 1536 /* Rx Buffer size */
+#define R8169_TX_RING_BYTES (NUM_TX_DESC * sizeof(struct TxDesc))
+#define R8169_RX_RING_BYTES (NUM_RX_DESC * sizeof(struct RxDesc))
+
+#define TX_RING_ALIGN 256
+#define RX_RING_ALIGN 256
+
+#define RTL8169_TX_TIMEOUT (6*HZ)
+#define RTL8169_PHY_TIMEOUT (10*HZ)
+
+#define RTL_EEPROM_SIG cpu_to_le32(0x8129)
+#define RTL_EEPROM_SIG_MASK cpu_to_le32(0xffff)
+#define RTL_EEPROM_SIG_ADDR 0x0000
+
+/* write/read MMIO register */
+#define RTL_W8(reg, val8) writeb ((val8), ioaddr + (reg))
+#define RTL_W16(reg, val16) writew ((val16), ioaddr + (reg))
+#define RTL_W32(reg, val32) writel ((val32), ioaddr + (reg))
+#define RTL_R8(reg) readb (ioaddr + (reg))
+#define RTL_R16(reg) readw (ioaddr + (reg))
+#define RTL_R32(reg) ((unsigned long) readl (ioaddr + (reg)))
+
+enum mac_version {
+ RTL_GIGA_MAC_VER_01 = 0x01, // 8169
+ RTL_GIGA_MAC_VER_02 = 0x02, // 8169S
+ RTL_GIGA_MAC_VER_03 = 0x03, // 8110S
+ RTL_GIGA_MAC_VER_04 = 0x04, // 8169SB
+ RTL_GIGA_MAC_VER_05 = 0x05, // 8110SCd
+ RTL_GIGA_MAC_VER_06 = 0x06, // 8110SCe
+ RTL_GIGA_MAC_VER_07 = 0x07, // 8102e
+ RTL_GIGA_MAC_VER_08 = 0x08, // 8102e
+ RTL_GIGA_MAC_VER_09 = 0x09, // 8102e
+ RTL_GIGA_MAC_VER_10 = 0x0a, // 8101e
+ RTL_GIGA_MAC_VER_11 = 0x0b, // 8168Bb
+ RTL_GIGA_MAC_VER_12 = 0x0c, // 8168Be
+ RTL_GIGA_MAC_VER_13 = 0x0d, // 8101Eb
+ RTL_GIGA_MAC_VER_14 = 0x0e, // 8101 ?
+ RTL_GIGA_MAC_VER_15 = 0x0f, // 8101 ?
+ RTL_GIGA_MAC_VER_16 = 0x11, // 8101Ec
+ RTL_GIGA_MAC_VER_17 = 0x10, // 8168Bf
+ RTL_GIGA_MAC_VER_18 = 0x12, // 8168CP
+ RTL_GIGA_MAC_VER_19 = 0x13, // 8168C
+ RTL_GIGA_MAC_VER_20 = 0x14, // 8168C
+ RTL_GIGA_MAC_VER_21 = 0x15, // 8168C
+ RTL_GIGA_MAC_VER_22 = 0x16, // 8168C
+ RTL_GIGA_MAC_VER_23 = 0x17, // 8168CP
+ RTL_GIGA_MAC_VER_24 = 0x18, // 8168CP
+ RTL_GIGA_MAC_VER_25 = 0x19, // 8168D
+};
+
+#define _R(NAME,MAC,MASK) \
+ { .name = NAME, .mac_version = MAC, .RxConfigMask = MASK }
+
+static const struct {
+ const char *name;
+ u8 mac_version;
+ u32 RxConfigMask; /* Clears the bits supported by this chip */
+} rtl_chip_info[] = {
+ _R("RTL8169", RTL_GIGA_MAC_VER_01, 0xff7e1880), // 8169
+ _R("RTL8169s", RTL_GIGA_MAC_VER_02, 0xff7e1880), // 8169S
+ _R("RTL8110s", RTL_GIGA_MAC_VER_03, 0xff7e1880), // 8110S
+ _R("RTL8169sb/8110sb", RTL_GIGA_MAC_VER_04, 0xff7e1880), // 8169SB
+ _R("RTL8169sc/8110sc", RTL_GIGA_MAC_VER_05, 0xff7e1880), // 8110SCd
+ _R("RTL8169sc/8110sc", RTL_GIGA_MAC_VER_06, 0xff7e1880), // 8110SCe
+ _R("RTL8102e", RTL_GIGA_MAC_VER_07, 0xff7e1880), // PCI-E
+ _R("RTL8102e", RTL_GIGA_MAC_VER_08, 0xff7e1880), // PCI-E
+ _R("RTL8102e", RTL_GIGA_MAC_VER_09, 0xff7e1880), // PCI-E
+ _R("RTL8101e", RTL_GIGA_MAC_VER_10, 0xff7e1880), // PCI-E
+ _R("RTL8168b/8111b", RTL_GIGA_MAC_VER_11, 0xff7e1880), // PCI-E
+ _R("RTL8168b/8111b", RTL_GIGA_MAC_VER_12, 0xff7e1880), // PCI-E
+ _R("RTL8101e", RTL_GIGA_MAC_VER_13, 0xff7e1880), // PCI-E 8139
+ _R("RTL8100e", RTL_GIGA_MAC_VER_14, 0xff7e1880), // PCI-E 8139
+ _R("RTL8100e", RTL_GIGA_MAC_VER_15, 0xff7e1880), // PCI-E 8139
+ _R("RTL8168b/8111b", RTL_GIGA_MAC_VER_17, 0xff7e1880), // PCI-E
+ _R("RTL8101e", RTL_GIGA_MAC_VER_16, 0xff7e1880), // PCI-E
+ _R("RTL8168cp/8111cp", RTL_GIGA_MAC_VER_18, 0xff7e1880), // PCI-E
+ _R("RTL8168c/8111c", RTL_GIGA_MAC_VER_19, 0xff7e1880), // PCI-E
+ _R("RTL8168c/8111c", RTL_GIGA_MAC_VER_20, 0xff7e1880), // PCI-E
+ _R("RTL8168c/8111c", RTL_GIGA_MAC_VER_21, 0xff7e1880), // PCI-E
+ _R("RTL8168c/8111c", RTL_GIGA_MAC_VER_22, 0xff7e1880), // PCI-E
+ _R("RTL8168cp/8111cp", RTL_GIGA_MAC_VER_23, 0xff7e1880), // PCI-E
+ _R("RTL8168cp/8111cp", RTL_GIGA_MAC_VER_24, 0xff7e1880), // PCI-E
+ _R("RTL8168d/8111d", RTL_GIGA_MAC_VER_25, 0xff7e1880) // PCI-E
+};
+#undef _R
+
+enum cfg_version {
+ RTL_CFG_0 = 0x00,
+ RTL_CFG_1,
+ RTL_CFG_2
+};
+
+#if 0
+/** Device Table from Linux Driver **/
+static struct pci_device_id rtl8169_pci_tbl[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8129), 0, 0, RTL_CFG_0 },
+ { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8136), 0, 0, RTL_CFG_2 },
+ { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8167), 0, 0, RTL_CFG_0 },
+ { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8168), 0, 0, RTL_CFG_1 },
+ { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8169), 0, 0, RTL_CFG_0 },
+ { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4300), 0, 0, RTL_CFG_0 },
+ { PCI_DEVICE(PCI_VENDOR_ID_AT, 0xc107), 0, 0, RTL_CFG_0 },
+ { PCI_DEVICE(0x16ec, 0x0116), 0, 0, RTL_CFG_0 },
+ { PCI_VENDOR_ID_LINKSYS, 0x1032,
+ PCI_ANY_ID, 0x0024, 0, 0, RTL_CFG_0 },
+ { 0x0001, 0x8168,
+ PCI_ANY_ID, 0x2410, 0, 0, RTL_CFG_2 },
+ {0,},
+};
+#endif
+
+enum rtl_registers {
+ MAC0 = 0, /* Ethernet hardware address. */
+ MAC4 = 4,
+ MAR0 = 8, /* Multicast filter. */
+ CounterAddrLow = 0x10,
+ CounterAddrHigh = 0x14,
+ TxDescStartAddrLow = 0x20,
+ TxDescStartAddrHigh = 0x24,
+ TxHDescStartAddrLow = 0x28,
+ TxHDescStartAddrHigh = 0x2c,
+ FLASH = 0x30,
+ ERSR = 0x36,
+ ChipCmd = 0x37,
+ TxPoll = 0x38,
+ IntrMask = 0x3c,
+ IntrStatus = 0x3e,
+ TxConfig = 0x40,
+ RxConfig = 0x44,
+ RxMissed = 0x4c,
+ Cfg9346 = 0x50,
+ Config0 = 0x51,
+ Config1 = 0x52,
+ Config2 = 0x53,
+ Config3 = 0x54,
+ Config4 = 0x55,
+ Config5 = 0x56,
+ MultiIntr = 0x5c,
+ PHYAR = 0x60,
+ PHYstatus = 0x6c,
+ RxMaxSize = 0xda,
+ CPlusCmd = 0xe0,
+ IntrMitigate = 0xe2,
+ RxDescAddrLow = 0xe4,
+ RxDescAddrHigh = 0xe8,
+ EarlyTxThres = 0xec,
+ FuncEvent = 0xf0,
+ FuncEventMask = 0xf4,
+ FuncPresetState = 0xf8,
+ FuncForceEvent = 0xfc,
+};
+
+enum rtl8110_registers {
+ TBICSR = 0x64,
+ TBI_ANAR = 0x68,
+ TBI_LPAR = 0x6a,
+};
+
+enum rtl8168_8101_registers {
+ CSIDR = 0x64,
+ CSIAR = 0x68,
+#define CSIAR_FLAG 0x80000000
+#define CSIAR_WRITE_CMD 0x80000000
+#define CSIAR_BYTE_ENABLE 0x0f
+#define CSIAR_BYTE_ENABLE_SHIFT 12
+#define CSIAR_ADDR_MASK 0x0fff
+
+ EPHYAR = 0x80,
+#define EPHYAR_FLAG 0x80000000
+#define EPHYAR_WRITE_CMD 0x80000000
+#define EPHYAR_REG_MASK 0x1f
+#define EPHYAR_REG_SHIFT 16
+#define EPHYAR_DATA_MASK 0xffff
+ DBG_REG = 0xd1,
+#define FIX_NAK_1 (1 << 4)
+#define FIX_NAK_2 (1 << 3)
+};
+
+enum rtl_register_content {
+ /* InterruptStatusBits */
+ SYSErr = 0x8000,
+ PCSTimeout = 0x4000,
+ SWInt = 0x0100,
+ TxDescUnavail = 0x0080,
+ RxFIFOOver = 0x0040,
+ LinkChg = 0x0020,
+ RxOverflow = 0x0010,
+ TxErr = 0x0008,
+ TxOK = 0x0004,
+ RxErr = 0x0002,
+ RxOK = 0x0001,
+
+ /* RxStatusDesc */
+ RxFOVF = (1 << 23),
+ RxRWT = (1 << 22),
+ RxRES = (1 << 21),
+ RxRUNT = (1 << 20),
+ RxCRC = (1 << 19),
+
+ /* ChipCmdBits */
+ CmdReset = 0x10,
+ CmdRxEnb = 0x08,
+ CmdTxEnb = 0x04,
+ RxBufEmpty = 0x01,
+
+ /* TXPoll register p.5 */
+ HPQ = 0x80, /* Poll cmd on the high prio queue */
+ NPQ = 0x40, /* Poll cmd on the low prio queue */
+ FSWInt = 0x01, /* Forced software interrupt */
+
+ /* Cfg9346Bits */
+ Cfg9346_Lock = 0x00,
+ Cfg9346_Unlock = 0xc0,
+
+ /* rx_mode_bits */
+ AcceptErr = 0x20,
+ AcceptRunt = 0x10,
+ AcceptBroadcast = 0x08,
+ AcceptMulticast = 0x04,
+ AcceptMyPhys = 0x02,
+ AcceptAllPhys = 0x01,
+
+ /* RxConfigBits */
+ RxCfgFIFOShift = 13,
+ RxCfgDMAShift = 8,
+
+ /* TxConfigBits */
+ TxInterFrameGapShift = 24,
+ TxDMAShift = 8, /* DMA burst value (0-7) is shift this many bits */
+
+ /* Config1 register p.24 */
+ LEDS1 = (1 << 7),
+ LEDS0 = (1 << 6),
+ MSIEnable = (1 << 5), /* Enable Message Signaled Interrupt */
+ Speed_down = (1 << 4),
+ MEMMAP = (1 << 3),
+ IOMAP = (1 << 2),
+ VPD = (1 << 1),
+ PMEnable = (1 << 0), /* Power Management Enable */
+
+ /* Config2 register p. 25 */
+ PCI_Clock_66MHz = 0x01,
+ PCI_Clock_33MHz = 0x00,
+
+ /* Config3 register p.25 */
+ MagicPacket = (1 << 5), /* Wake up when receives a Magic Packet */
+ LinkUp = (1 << 4), /* Wake up when the cable connection is re-established */
+ Beacon_en = (1 << 0), /* 8168 only. Reserved in the 8168b */
+
+ /* Config5 register p.27 */
+ BWF = (1 << 6), /* Accept Broadcast wakeup frame */
+ MWF = (1 << 5), /* Accept Multicast wakeup frame */
+ UWF = (1 << 4), /* Accept Unicast wakeup frame */
+ LanWake = (1 << 1), /* LanWake enable/disable */
+ PMEStatus = (1 << 0), /* PME status can be reset by PCI RST# */
+
+ /* TBICSR p.28 */
+ TBIReset = 0x80000000,
+ TBILoopback = 0x40000000,
+ TBINwEnable = 0x20000000,
+ TBINwRestart = 0x10000000,
+ TBILinkOk = 0x02000000,
+ TBINwComplete = 0x01000000,
+
+ /* CPlusCmd p.31 */
+ EnableBist = (1 << 15), // 8168 8101
+ Mac_dbgo_oe = (1 << 14), // 8168 8101
+ Normal_mode = (1 << 13), // unused
+ Force_half_dup = (1 << 12), // 8168 8101
+ Force_rxflow_en = (1 << 11), // 8168 8101
+ Force_txflow_en = (1 << 10), // 8168 8101
+ Cxpl_dbg_sel = (1 << 9), // 8168 8101
+ ASF = (1 << 8), // 8168 8101
+ PktCntrDisable = (1 << 7), // 8168 8101
+ Mac_dbgo_sel = 0x001c, // 8168
+ RxVlan = (1 << 6),
+ RxChkSum = (1 << 5),
+ PCIDAC = (1 << 4),
+ PCIMulRW = (1 << 3),
+ INTT_0 = 0x0000, // 8168
+ INTT_1 = 0x0001, // 8168
+ INTT_2 = 0x0002, // 8168
+ INTT_3 = 0x0003, // 8168
+
+ /* rtl8169_PHYstatus */
+ TBI_Enable = 0x80,
+ TxFlowCtrl = 0x40,
+ RxFlowCtrl = 0x20,
+ _1000bpsF = 0x10,
+ _100bps = 0x08,
+ _10bps = 0x04,
+ LinkStatus = 0x02,
+ FullDup = 0x01,
+
+ /* _TBICSRBit */
+ TBILinkOK = 0x02000000,
+
+ /* DumpCounterCommand */
+ CounterDump = 0x8,
+};
+
+enum desc_status_bit {
+ DescOwn = (1 << 31), /* Descriptor is owned by NIC */
+ RingEnd = (1 << 30), /* End of descriptor ring */
+ FirstFrag = (1 << 29), /* First segment of a packet */
+ LastFrag = (1 << 28), /* Final segment of a packet */
+
+ /* Tx private */
+ LargeSend = (1 << 27), /* TCP Large Send Offload (TSO) */
+ MSSShift = 16, /* MSS value position */
+ MSSMask = 0xfff, /* MSS value + LargeSend bit: 12 bits */
+ IPCS = (1 << 18), /* Calculate IP checksum */
+ UDPCS = (1 << 17), /* Calculate UDP/IP checksum */
+ TCPCS = (1 << 16), /* Calculate TCP/IP checksum */
+ TxVlanTag = (1 << 17), /* Add VLAN tag */
+
+ /* Rx private */
+ PID1 = (1 << 18), /* Protocol ID bit 1/2 */
+ PID0 = (1 << 17), /* Protocol ID bit 2/2 */
+
+#define RxProtoUDP (PID1)
+#define RxProtoTCP (PID0)
+#define RxProtoIP (PID1 | PID0)
+#define RxProtoMask RxProtoIP
+
+ IPFail = (1 << 16), /* IP checksum failed */
+ UDPFail = (1 << 15), /* UDP/IP checksum failed */
+ TCPFail = (1 << 14), /* TCP/IP checksum failed */
+ RxVlanTag = (1 << 16), /* VLAN tag available */
+};
+
+#define RsvdMask 0x3fffc000
+
+struct TxDesc {
+ volatile uint32_t opts1;
+ volatile uint32_t opts2;
+ volatile uint32_t addr_lo;
+ volatile uint32_t addr_hi;
+};
+
+struct RxDesc {
+ volatile uint32_t opts1;
+ volatile uint32_t opts2;
+ volatile uint32_t addr_lo;
+ volatile uint32_t addr_hi;
+};
+
+enum features {
+ RTL_FEATURE_WOL = (1 << 0),
+ RTL_FEATURE_MSI = (1 << 1),
+ RTL_FEATURE_GMII = (1 << 2),
+};
+
+static void rtl_hw_start_8169(struct net_device *);
+static void rtl_hw_start_8168(struct net_device *);
+static void rtl_hw_start_8101(struct net_device *);
+
+struct rtl8169_private {
+
+ struct pci_device *pci_dev;
+ struct net_device *netdev;
+ uint8_t *hw_addr;
+ void *mmio_addr;
+ uint32_t irqno;
+
+ int chipset;
+ int mac_version;
+ int cfg_index;
+ u16 intr_event;
+
+ struct io_buffer *tx_iobuf[NUM_TX_DESC];
+ struct io_buffer *rx_iobuf[NUM_RX_DESC];
+
+ struct TxDesc *tx_base;
+ struct RxDesc *rx_base;
+
+ uint32_t tx_curr;
+ uint32_t rx_curr;
+
+ uint32_t tx_tail;
+
+ uint32_t tx_fill_ctr;
+
+ u16 cp_cmd;
+
+ int phy_auto_nego_reg;
+ int phy_1000_ctrl_reg;
+
+ int ( *set_speed ) (struct net_device *, u8 autoneg, u16 speed, u8 duplex );
+ void ( *phy_reset_enable ) ( void *ioaddr );
+ void ( *hw_start ) ( struct net_device * );
+ unsigned int ( *phy_reset_pending ) ( void *ioaddr );
+ unsigned int ( *link_ok ) ( void *ioaddr );
+
+ int pcie_cap;
+
+ unsigned features;
+
+};
+
+static const unsigned int rtl8169_rx_config =
+ (RX_FIFO_THRESH << RxCfgFIFOShift) | (RX_DMA_BURST << RxCfgDMAShift);
+
+#endif /* _R8169_H_ */
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * c-indent-level: 8
+ * tab-width: 8
+ * End:
+ */
diff --git a/gpxe/src/drivers/net/rtl8139.c b/gpxe/src/drivers/net/rtl8139.c
index 509047a9..2dff324c 100644
--- a/gpxe/src/drivers/net/rtl8139.c
+++ b/gpxe/src/drivers/net/rtl8139.c
@@ -69,7 +69,8 @@
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
-#include <io.h>
+#include <string.h>
+#include <gpxe/io.h>
#include <errno.h>
#include <unistd.h>
#include <byteswap.h>
diff --git a/gpxe/src/drivers/net/tg3.c b/gpxe/src/drivers/net/tg3.c
index bda832e8..bcb9dda7 100644
--- a/gpxe/src/drivers/net/tg3.c
+++ b/gpxe/src/drivers/net/tg3.c
@@ -3399,6 +3399,7 @@ PCI_ROM(0x14e4, 0x1677, "tg3-5751", "Broadcom Tigon 3 5751"),
PCI_ROM(0x14e4, 0x167a, "tg3-5754", "Broadcom Tigon 3 5754"),
PCI_ROM(0x14e4, 0x1693, "tg3-5787", "Broadcom Tigon 3 5787"),
PCI_ROM(0x14e4, 0x1696, "tg3-5782", "Broadcom Tigon 3 5782"),
+PCI_ROM(0x14e4, 0x169a, "tg3-5786", "Broadcom Tigon 3 5786"),
PCI_ROM(0x14e4, 0x169c, "tg3-5788", "Broadcom Tigon 3 5788"),
PCI_ROM(0x14e4, 0x169d, "tg3-5789", "Broadcom Tigon 3 5789"),
PCI_ROM(0x14e4, 0x16a6, "tg3-5702X", "Broadcom Tigon 3 5702X"),
diff --git a/gpxe/src/drivers/net/via-rhine.c b/gpxe/src/drivers/net/via-rhine.c
index fb43a924..201ebb08 100644
--- a/gpxe/src/drivers/net/via-rhine.c
+++ b/gpxe/src/drivers/net/via-rhine.c
@@ -784,7 +784,7 @@ ReadMII (int byMIIIndex, int ioaddr)
char byMIIAdrbak;
char byMIICRbak;
char byMIItemp;
- tick_t ct;
+ unsigned long ct;
byMIIAdrbak = inb (byMIIAD);
byMIICRbak = inb (byMIICR);
@@ -800,7 +800,7 @@ ReadMII (int byMIIIndex, int ioaddr)
byMIItemp = byMIItemp & 0x40;
ct = currticks();
- while (byMIItemp != 0 && ct + 2*USECS_IN_MSEC < currticks())
+ while (byMIItemp != 0 && ct + 2*1000 < currticks())
{
byMIItemp = inb (byMIICR);
byMIItemp = byMIItemp & 0x40;
@@ -825,7 +825,7 @@ WriteMII (char byMIISetByte, char byMIISetBit, char byMIIOP, int ioaddr)
char byMIIAdrbak;
char byMIICRbak;
char byMIItemp;
- tick_t ct;
+ unsigned long ct;
byMIIAdrbak = inb (byMIIAD);
@@ -842,7 +842,7 @@ WriteMII (char byMIISetByte, char byMIISetBit, char byMIIOP, int ioaddr)
byMIItemp = byMIItemp & 0x40;
ct = currticks();
- while (byMIItemp != 0 && ct + 2*USECS_IN_MSEC < currticks())
+ while (byMIItemp != 0 && ct + 2*1000 < currticks())
{
byMIItemp = inb (byMIICR);
byMIItemp = byMIItemp & 0x40;
@@ -872,7 +872,7 @@ WriteMII (char byMIISetByte, char byMIISetBit, char byMIIOP, int ioaddr)
byMIItemp = byMIItemp & 0x20;
ct = currticks();
- while (byMIItemp != 0 && ct + 2*USECS_IN_MSEC < currticks())
+ while (byMIItemp != 0 && ct + 2*1000 < currticks())
{
byMIItemp = inb (byMIICR);
byMIItemp = byMIItemp & 0x20;
@@ -1008,7 +1008,7 @@ rhine_probe1 (struct nic *nic, struct pci_device *pci, int ioaddr, int chip_id,
unsigned char mode3_reg;
if (rhine_debug > 0 && did_version++ == 0)
- printf (version);
+ printf ("%s",version);
// get revision id.
pci_read_config_byte(pci, PCI_REVISION, &revision_id);
@@ -1346,7 +1346,7 @@ rhine_transmit (struct nic *nic,
unsigned char CR1bak;
unsigned char CR0bak;
unsigned int nstype;
- tick_t ct;
+ unsigned long ct;
/*printf ("rhine_transmit\n"); */
@@ -1390,7 +1390,7 @@ rhine_transmit (struct nic *nic,
ct = currticks();
/* Wait until transmit is finished or timeout*/
while((tp->tx_ring[entry].tx_status.bits.own_bit !=0) &&
- ct + 10*USECS_IN_MSEC < currticks())
+ ct + 10*1000 < currticks())
;
if(tp->tx_ring[entry].tx_status.bits.terr == 0)
diff --git a/gpxe/src/drivers/net/virtio-net.c b/gpxe/src/drivers/net/virtio-net.c
index 4ec154df..68c84d79 100644
--- a/gpxe/src/drivers/net/virtio-net.c
+++ b/gpxe/src/drivers/net/virtio-net.c
@@ -187,6 +187,8 @@ static int vring_get_buf(int queue_index, unsigned int *len)
u32 id;
int ret;
+ BUG_ON(!vring_more_used(queue_index));
+
elem = &vr->used->ring[last_used_idx[queue_index] % vr->num];
wmb();
id = elem->id;
@@ -365,6 +367,8 @@ static void virtnet_transmit(struct nic *nic, const char *destaddr,
vring_add_buf(TX_INDEX, 0, 0);
+ vring_kick(nic, TX_INDEX, 1);
+
/*
* http://www.etherboot.org/wiki/dev/devmanual
*
@@ -372,13 +376,11 @@ static void virtnet_transmit(struct nic *nic, const char *destaddr,
* before returning from this routine"
*/
- while (vring_more_used(TX_INDEX)) {
+ while (!vring_more_used(TX_INDEX)) {
mb();
udelay(10);
}
- vring_kick(nic, TX_INDEX, 1);
-
/* free desc */
(void)vring_get_buf(TX_INDEX, NULL);
diff --git a/gpxe/src/drivers/net/w89c840.c b/gpxe/src/drivers/net/w89c840.c
index 14497640..5abc0b35 100644
--- a/gpxe/src/drivers/net/w89c840.c
+++ b/gpxe/src/drivers/net/w89c840.c
@@ -112,7 +112,7 @@ static const char *w89c840_version = "driver Version 0.94 - December 12, 2003";
/* Operational parameters that usually are not changed. */
/* Time in jiffies before concluding the transmitter is hung. */
-#define TX_TIMEOUT (10*USECS_IN_MSEC)
+#define TX_TIMEOUT (10*1000)
#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/
@@ -486,7 +486,7 @@ static void w89c840_transmit(
/* send the packet to destination */
unsigned entry;
int transmit_status;
- tick_t ct;
+ unsigned long ct;
/* Caution: the write order is important here, set the field
with the "ownership" bits last. */
diff --git a/gpxe/src/hci/commands/config_cmd.c b/gpxe/src/hci/commands/config_cmd.c
index 660c6423..87abb05a 100644
--- a/gpxe/src/hci/commands/config_cmd.c
+++ b/gpxe/src/hci/commands/config_cmd.c
@@ -16,7 +16,7 @@ static int config_exec ( int argc, char **argv ) {
}
settings_name = ( ( argc == 2 ) ? argv[1] : "" );
- settings = find_settings ( argv[1] );
+ settings = find_settings ( settings_name );
if ( ! settings ) {
printf ( "No such scope \"%s\"\n", settings_name );
return 1;
diff --git a/gpxe/src/image/efi_image.c b/gpxe/src/image/efi_image.c
new file mode 100644
index 00000000..c80cd264
--- /dev/null
+++ b/gpxe/src/image/efi_image.c
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2008 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 <errno.h>
+#include <gpxe/efi/efi.h>
+#include <gpxe/image.h>
+#include <gpxe/features.h>
+
+FEATURE ( FEATURE_IMAGE, "EFI", DHCP_EB_FEATURE_EFI, 1 );
+
+struct image_type efi_image_type __image_type ( PROBE_NORMAL );
+
+/**
+ * Execute EFI image
+ *
+ * @v image EFI image
+ * @ret rc Return status code
+ */
+static int efi_image_exec ( struct image *image ) {
+ EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+ EFI_HANDLE handle;
+ UINTN exit_data_size;
+ CHAR16 *exit_data;
+ EFI_STATUS efirc;
+
+ /* Attempt loading image */
+ if ( ( efirc = bs->LoadImage ( FALSE, efi_image_handle, NULL,
+ user_to_virt ( image->data, 0 ),
+ image->len, &handle ) ) != 0 ) {
+ /* Not an EFI image */
+ DBGC ( image, "EFIIMAGE %p could not load: %lx\n",
+ image, efirc );
+ return -ENOEXEC;
+ }
+
+ /* Start the image */
+ if ( ( efirc = bs->StartImage ( handle, &exit_data_size,
+ &exit_data ) ) != 0 ) {
+ DBGC ( image, "EFIIMAGE %p returned with status %lx\n",
+ image, efirc );
+ goto done;
+ }
+
+ done:
+ /* Unload the image. We can't leave it loaded, because we
+ * have no "unload" operation.
+ */
+ bs->UnloadImage ( handle );
+
+ return EFIRC_TO_RC ( efirc );
+}
+
+/**
+ * Load EFI image into memory
+ *
+ * @v image EFI file
+ * @ret rc Return status code
+ */
+static int efi_image_load ( struct image *image ) {
+ EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+ EFI_HANDLE handle;
+ EFI_STATUS efirc;
+
+ /* Attempt loading image */
+ if ( ( efirc = bs->LoadImage ( FALSE, efi_image_handle, NULL,
+ user_to_virt ( image->data, 0 ),
+ image->len, &handle ) ) != 0 ) {
+ /* Not an EFI image */
+ DBGC ( image, "EFIIMAGE %p could not load: %lx\n",
+ image, efirc );
+ return -ENOEXEC;
+ }
+
+ /* This is an EFI image */
+ if ( ! image->type )
+ image->type = &efi_image_type;
+
+ /* Unload the image. We can't leave it loaded, because we
+ * have no "unload" operation.
+ */
+ bs->UnloadImage ( handle );
+
+ return 0;
+}
+
+/** EFI image type */
+struct image_type efi_image_type __image_type ( PROBE_NORMAL ) = {
+ .name = "EFI",
+ .load = efi_image_load,
+ .exec = efi_image_exec,
+};
diff --git a/gpxe/src/include/compiler.h b/gpxe/src/include/compiler.h
index 8ab7b8ae..b6a6f8e2 100644
--- a/gpxe/src/include/compiler.h
+++ b/gpxe/src/include/compiler.h
@@ -131,11 +131,26 @@ extern void dbg_decolourise ( void );
extern void dbg_hex_dump_da ( unsigned long dispaddr,
const void *data, unsigned long len );
-/* Compatibility with existing Makefile */
#if DEBUG_SYMBOL
-#define DBGLVL DEBUG_SYMBOL
+#define DBGLVL_MAX DEBUG_SYMBOL
+#else
+#define DBGLVL_MAX 0
+#endif
+
+/* Allow for selective disabling of enabled debug levels */
+#if DBGLVL_MAX
+int __debug_disable;
+#define DBGLVL ( DBGLVL_MAX & ~__debug_disable )
+#define DBG_DISABLE( level ) do { \
+ __debug_disable |= ( (level) & DBGLVL_MAX ); \
+ } while ( 0 )
+#define DBG_ENABLE( level ) do { \
+ __debug_disable &= ~( (level) & DBGLVL_MAX ); \
+ } while ( 0 )
#else
#define DBGLVL 0
+#define DBG_DISABLE( level ) do { } while ( 0 )
+#define DBG_ENABLE( level ) do { } while ( 0 )
#endif
#define DBGLVL_LOG 1
@@ -325,6 +340,9 @@ extern void dbg_hex_dump_da ( unsigned long dispaddr,
/** Declare a data structure to be aligned with 16-byte alignment */
#define __aligned __attribute__ (( aligned ( 16 ) ))
+/** Declare a function to be always inline */
+#define __always_inline __attribute__ (( always_inline ))
+
/**
* Shared data.
*
diff --git a/gpxe/src/include/gpxe/api.h b/gpxe/src/include/gpxe/api.h
new file mode 100644
index 00000000..df5d1ae3
--- /dev/null
+++ b/gpxe/src/include/gpxe/api.h
@@ -0,0 +1,82 @@
+#ifndef _GPXE_API_H
+#define _GPXE_API_H
+
+/** @file
+ *
+ * gPXE internal APIs
+ *
+ * There are various formally-defined APIs internal to gPXE, with
+ * several differing implementations specific to particular execution
+ * environments (e.g. PC BIOS, EFI, LinuxBIOS).
+ *
+ */
+
+/** @defgroup Single-implementation APIs
+ *
+ * These are APIs for which only a single implementation may be
+ * compiled in at any given time.
+ *
+ * @{
+ */
+
+/**
+ * Calculate function implementation name
+ *
+ * @v _prefix Subsystem prefix
+ * @v _api_func API function
+ * @ret _subsys_func Subsystem API function
+ *
+ * The subsystem prefix should be an empty string for the currently
+ * selected subsystem, and should be a subsystem-unique string for all
+ * other subsystems.
+ */
+#define SINGLE_API_NAME( _prefix, _api_func ) _prefix ## _api_func
+
+/**
+ * Calculate static inline function name
+ *
+ * @v _prefix Subsystem prefix
+ * @v _api_func API function
+ * @ret _subsys_func Subsystem API function
+ */
+#define SINGLE_API_INLINE( _prefix, _api_func ) \
+ SINGLE_API_NAME ( _prefix, _api_func )
+
+/**
+ * Provide an API implementation
+ *
+ * @v _prefix Subsystem prefix
+ * @v _api_func API function
+ * @v _func Implementing function
+ */
+#define PROVIDE_SINGLE_API( _prefix, _api_func, _func ) \
+ /* Ensure that _api_func exists */ \
+ typeof ( _api_func ) _api_func; \
+ /* Ensure that _func exists */ \
+ typeof ( _func ) _func; \
+ /* Ensure that _func is type-compatible with _api_func */ \
+ typeof ( _api_func ) _func; \
+ /* Ensure that _subsys_func is non-static */ \
+ extern typeof ( _api_func ) SINGLE_API_NAME ( _prefix, _api_func ); \
+ /* Provide symbol alias from _subsys_func to _func */ \
+ typeof ( _api_func ) SINGLE_API_NAME ( _prefix, _api_func ) \
+ __attribute__ (( alias ( #_func ) ));
+
+/**
+ * Provide a static inline API implementation
+ *
+ * @v _prefix Subsystem prefix
+ * @v _api_func API function
+ */
+#define PROVIDE_SINGLE_API_INLINE( _prefix, _api_func ) \
+ /* Ensure that _api_func exists */ \
+ typeof ( _api_func ) _api_func; \
+ /* Ensure that _subsys_func exists and is static */ \
+ static typeof ( SINGLE_API_INLINE ( _prefix, _api_func ) ) \
+ SINGLE_API_INLINE ( _prefix, _api_func ); \
+ /* Ensure that _subsys_func is type-compatible with _api_func */ \
+ typeof ( _api_func ) SINGLE_API_INLINE ( _prefix, _api_func );
+
+/** @} */
+
+#endif /* _GPXE_API_H */
diff --git a/gpxe/src/include/gpxe/bitops.h b/gpxe/src/include/gpxe/bitops.h
index f95af7d3..5405c854 100644
--- a/gpxe/src/include/gpxe/bitops.h
+++ b/gpxe/src/include/gpxe/bitops.h
@@ -1,27 +1,228 @@
#ifndef _GPXE_BITOPS_H
#define _GPXE_BITOPS_H
-/** @file
+/*
+ * Copyright (C) 2008 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.
+ */
+
+/**
+ * @file
*
* Bit operations
+ *
*/
#include <stdint.h>
+#include <byteswap.h>
+
+/* Endianness selection.
+ *
+ * This is a property of the NIC, not a property of the host CPU.
+ */
+#ifdef BITOPS_LITTLE_ENDIAN
+#define cpu_to_BIT64 cpu_to_le64
+#define cpu_to_BIT32 cpu_to_le32
+#define BIT64_to_cpu le64_to_cpu
+#define BIT32_to_cpu le32_to_cpu
+#endif
+#ifdef BITOPS_BIG_ENDIAN
+#define cpu_to_BIT64 cpu_to_be64
+#define cpu_to_BIT32 cpu_to_be32
+#define BIT64_to_cpu be64_to_cpu
+#define BIT32_to_cpu be32_to_cpu
+#endif
+
+/** Datatype used to represent a bit in the pseudo-structures */
+typedef unsigned char pseudo_bit_t;
+
+/**
+ * Wrapper structure for pseudo_bit_t structures
+ *
+ * This structure provides a wrapper around pseudo_bit_t structures.
+ * It has the correct size, and also encapsulates type information
+ * about the underlying pseudo_bit_t-based structure, which allows the
+ * BIT_FILL() etc. macros to work without requiring explicit type
+ * information.
+ */
+#define PSEUDO_BIT_STRUCT( _structure ) \
+ union { \
+ uint8_t bytes[ sizeof ( _structure ) / 8 ]; \
+ uint32_t dwords[ sizeof ( _structure ) / 32 ]; \
+ uint64_t qwords[ sizeof ( _structure ) / 64 ]; \
+ _structure *dummy[0]; \
+ } u
+
+/** Get pseudo_bit_t structure type from wrapper structure pointer */
+#define PSEUDO_BIT_STRUCT_TYPE( _ptr ) \
+ typeof ( *((_ptr)->u.dummy[0]) )
+
+/** Bit offset of a field within a pseudo_bit_t structure */
+#define BIT_OFFSET( _ptr, _field ) \
+ offsetof ( PSEUDO_BIT_STRUCT_TYPE ( _ptr ), _field )
+
+/** Bit width of a field within a pseudo_bit_t structure */
+#define BIT_WIDTH( _ptr, _field ) \
+ sizeof ( ( ( PSEUDO_BIT_STRUCT_TYPE ( _ptr ) * ) NULL )->_field )
+
+/** Qword offset of a field within a pseudo_bit_t structure */
+#define QWORD_OFFSET( _ptr, _field ) \
+ ( BIT_OFFSET ( _ptr, _field ) / 64 )
+
+/** Qword bit offset of a field within a pseudo_bit_t structure */
+#define QWORD_BIT_OFFSET( _ptr, _index, _field ) \
+ ( BIT_OFFSET ( _ptr, _field ) - ( 64 * (_index) ) )
+
+/** Bit mask for a field within a pseudo_bit_t structure */
+#define BIT_MASK( _ptr, _field ) \
+ ( ( ~( ( uint64_t ) 0 ) ) >> \
+ ( 64 - BIT_WIDTH ( _ptr, _field ) ) )
+
+/*
+ * Assemble native-endian qword from named fields and values
+ *
+ */
+
+#define BIT_ASSEMBLE_1( _ptr, _index, _field, _value ) \
+ ( ( ( uint64_t) (_value) ) << \
+ QWORD_BIT_OFFSET ( _ptr, _index, _field ) )
+
+#define BIT_ASSEMBLE_2( _ptr, _index, _field, _value, ... ) \
+ ( BIT_ASSEMBLE_1 ( _ptr, _index, _field, _value ) | \
+ BIT_ASSEMBLE_1 ( _ptr, _index, __VA_ARGS__ ) )
+
+#define BIT_ASSEMBLE_3( _ptr, _index, _field, _value, ... ) \
+ ( BIT_ASSEMBLE_1 ( _ptr, _index, _field, _value ) | \
+ BIT_ASSEMBLE_2 ( _ptr, _index, __VA_ARGS__ ) )
+
+#define BIT_ASSEMBLE_4( _ptr, _index, _field, _value, ... ) \
+ ( BIT_ASSEMBLE_1 ( _ptr, _index, _field, _value ) | \
+ BIT_ASSEMBLE_3 ( _ptr, _index, __VA_ARGS__ ) )
+
+#define BIT_ASSEMBLE_5( _ptr, _index, _field, _value, ... ) \
+ ( BIT_ASSEMBLE_1 ( _ptr, _index, _field, _value ) | \
+ BIT_ASSEMBLE_4 ( _ptr, _index, __VA_ARGS__ ) )
+
+#define BIT_ASSEMBLE_6( _ptr, _index, _field, _value, ... ) \
+ ( BIT_ASSEMBLE_1 ( _ptr, _index, _field, _value ) | \
+ BIT_ASSEMBLE_5 ( _ptr, _index, __VA_ARGS__ ) )
+
+#define BIT_ASSEMBLE_7( _ptr, _index, _field, _value, ... ) \
+ ( BIT_ASSEMBLE_1 ( _ptr, _index, _field, _value ) | \
+ BIT_ASSEMBLE_6 ( _ptr, _index, __VA_ARGS__ ) )
+
+/*
+ * Build native-endian (positive) qword bitmasks from named fields
+ *
+ */
+
+#define BIT_MASK_1( _ptr, _index, _field ) \
+ ( BIT_MASK ( _ptr, _field ) << \
+ QWORD_BIT_OFFSET ( _ptr, _index, _field ) )
+
+#define BIT_MASK_2( _ptr, _index, _field, ... ) \
+ ( BIT_MASK_1 ( _ptr, _index, _field ) | \
+ BIT_MASK_1 ( _ptr, _index, __VA_ARGS__ ) )
+
+#define BIT_MASK_3( _ptr, _index, _field, ... ) \
+ ( BIT_MASK_1 ( _ptr, _index, _field ) | \
+ BIT_MASK_2 ( _ptr, _index, __VA_ARGS__ ) )
+
+#define BIT_MASK_4( _ptr, _index, _field, ... ) \
+ ( BIT_MASK_1 ( _ptr, _index, _field ) | \
+ BIT_MASK_3 ( _ptr, _index, __VA_ARGS__ ) )
+
+#define BIT_MASK_5( _ptr, _index, _field, ... ) \
+ ( BIT_MASK_1 ( _ptr, _index, _field ) | \
+ BIT_MASK_4 ( _ptr, _index, __VA_ARGS__ ) )
+
+#define BIT_MASK_6( _ptr, _index, _field, ... ) \
+ ( BIT_MASK_1 ( _ptr, _index, _field ) | \
+ BIT_MASK_5 ( _ptr, _index, __VA_ARGS__ ) )
+
+#define BIT_MASK_7( _ptr, _index, _field, ... ) \
+ ( BIT_MASK_1 ( _ptr, _index, _field ) | \
+ BIT_MASK_6 ( _ptr, _index, __VA_ARGS__ ) )
+
+/*
+ * Populate little-endian qwords from named fields and values
+ *
+ */
+
+#define BIT_FILL( _ptr, _index, _assembled ) do { \
+ uint64_t *__ptr = &(_ptr)->u.qwords[(_index)]; \
+ uint64_t __assembled = (_assembled); \
+ *__ptr = cpu_to_BIT64 ( __assembled ); \
+ } while ( 0 )
+
+#define BIT_FILL_1( _ptr, _field1, ... ) \
+ BIT_FILL ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \
+ BIT_ASSEMBLE_1 ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \
+ _field1, __VA_ARGS__ ) )
+
+#define BIT_FILL_2( _ptr, _field1, ... ) \
+ BIT_FILL ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \
+ BIT_ASSEMBLE_2 ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \
+ _field1, __VA_ARGS__ ) )
+
+#define BIT_FILL_3( _ptr, _field1, ... ) \
+ BIT_FILL ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \
+ BIT_ASSEMBLE_3 ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \
+ _field1, __VA_ARGS__ ) )
+
+#define BIT_FILL_4( _ptr, _field1, ... ) \
+ BIT_FILL ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \
+ BIT_ASSEMBLE_4 ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \
+ _field1, __VA_ARGS__ ) )
+
+#define BIT_FILL_5( _ptr, _field1, ... ) \
+ BIT_FILL ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \
+ BIT_ASSEMBLE_5 ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \
+ _field1, __VA_ARGS__ ) )
-static inline uint32_t rol32 ( uint32_t data, unsigned int rotation ) {
- return ( ( data << rotation ) | ( data >> ( 32 - rotation ) ) );
-}
+#define BIT_FILL_6( _ptr, _field1, ... ) \
+ BIT_FILL ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \
+ BIT_ASSEMBLE_6 ( _ptr, QWORD_OFFSET ( _ptr, _field1 ), \
+ _field1, __VA_ARGS__ ) )
-static inline uint32_t ror32 ( uint32_t data, unsigned int rotation ) {
- return ( ( data >> rotation ) | ( data << ( 32 - rotation ) ) );
-}
+/** Extract value of named field */
+#define BIT_GET64( _ptr, _field ) \
+ ( { \
+ unsigned int __index = QWORD_OFFSET ( _ptr, _field ); \
+ uint64_t *__ptr = &(_ptr)->u.qwords[__index]; \
+ uint64_t __value = BIT64_to_cpu ( *__ptr ); \
+ __value >>= \
+ QWORD_BIT_OFFSET ( _ptr, __index, _field ); \
+ __value &= BIT_MASK ( _ptr, _field ); \
+ __value; \
+ } )
-static inline uint64_t rol64 ( uint64_t data, unsigned int rotation ) {
- return ( ( data << rotation ) | ( data >> ( 64 - rotation ) ) );
-}
+/** Extract value of named field (for fields up to the size of a long) */
+#define BIT_GET( _ptr, _field ) \
+ ( ( unsigned long ) BIT_GET64 ( _ptr, _field ) )
-static inline uint64_t ror64 ( uint64_t data, unsigned int rotation ) {
- return ( ( data >> rotation ) | ( data << ( 64 - rotation ) ) );
-}
+#define BIT_SET( _ptr, _field, _value ) do { \
+ unsigned int __index = QWORD_OFFSET ( _ptr, _field ); \
+ uint64_t *__ptr = &(_ptr)->u.qwords[__index]; \
+ unsigned int __shift = \
+ QWORD_BIT_OFFSET ( _ptr, __index, _field ); \
+ uint64_t __value = (_value); \
+ *__ptr &= cpu_to_BIT64 ( ~( BIT_MASK ( _ptr, _field ) << \
+ __shift ) ); \
+ *__ptr |= cpu_to_BIT64 ( __value << __shift ); \
+ } while ( 0 )
#endif /* _GPXE_BITOPS_H */
diff --git a/gpxe/src/include/gpxe/efi/Base.h b/gpxe/src/include/gpxe/efi/Base.h
new file mode 100644
index 00000000..cfb54a40
--- /dev/null
+++ b/gpxe/src/include/gpxe/efi/Base.h
@@ -0,0 +1,305 @@
+/** @file
+
+ Root include file for Mde Package Base type modules
+
+ This is the include file for any module of type base. Base modules only use
+ types defined via this include file and can be ported easily to any
+ environment. There are a set of base libraries in the Mde Package that can
+ be used to implement base modules.
+
+Copyright (c) 2006 - 2008, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+
+#ifndef __BASE_H__
+#define __BASE_H__
+
+//
+// Include processor specific binding
+//
+#include <gpxe/efi/ProcessorBind.h>
+
+typedef struct {
+ UINT32 Data1;
+ UINT16 Data2;
+ UINT16 Data3;
+ UINT8 Data4[8];
+} GUID;
+
+typedef UINT64 PHYSICAL_ADDRESS;
+
+///
+/// LIST_ENTRY definition
+///
+typedef struct _LIST_ENTRY LIST_ENTRY;
+
+struct _LIST_ENTRY {
+ LIST_ENTRY *ForwardLink;
+ LIST_ENTRY *BackLink;
+};
+
+//
+// Modifiers to absract standard types to aid in debug of problems
+//
+#define CONST const
+#define STATIC static
+#define VOID void
+
+//
+// Modifiers for Data Types used to self document code.
+// This concept is borrowed for UEFI specification.
+//
+#ifndef IN
+//
+// Some other envirnments use this construct, so #ifndef to prevent
+// mulitple definition.
+//
+#define IN
+#define OUT
+#define OPTIONAL
+#endif
+
+//
+// Constants. They may exist in other build structures, so #ifndef them.
+//
+#ifndef TRUE
+//
+// UEFI specification claims 1 and 0. We are concerned about the
+// complier portability so we did it this way.
+//
+#define TRUE ((BOOLEAN)(1==1))
+#endif
+
+#ifndef FALSE
+#define FALSE ((BOOLEAN)(0==1))
+#endif
+
+#ifndef NULL
+#define NULL ((VOID *) 0)
+#endif
+
+#define BIT0 0x00000001
+#define BIT1 0x00000002
+#define BIT2 0x00000004
+#define BIT3 0x00000008
+#define BIT4 0x00000010
+#define BIT5 0x00000020
+#define BIT6 0x00000040
+#define BIT7 0x00000080
+#define BIT8 0x00000100
+#define BIT9 0x00000200
+#define BIT10 0x00000400
+#define BIT11 0x00000800
+#define BIT12 0x00001000
+#define BIT13 0x00002000
+#define BIT14 0x00004000
+#define BIT15 0x00008000
+#define BIT16 0x00010000
+#define BIT17 0x00020000
+#define BIT18 0x00040000
+#define BIT19 0x00080000
+#define BIT20 0x00100000
+#define BIT21 0x00200000
+#define BIT22 0x00400000
+#define BIT23 0x00800000
+#define BIT24 0x01000000
+#define BIT25 0x02000000
+#define BIT26 0x04000000
+#define BIT27 0x08000000
+#define BIT28 0x10000000
+#define BIT29 0x20000000
+#define BIT30 0x40000000
+#define BIT31 0x80000000
+#define BIT32 0x0000000100000000UL
+#define BIT33 0x0000000200000000UL
+#define BIT34 0x0000000400000000UL
+#define BIT35 0x0000000800000000UL
+#define BIT36 0x0000001000000000UL
+#define BIT37 0x0000002000000000UL
+#define BIT38 0x0000004000000000UL
+#define BIT39 0x0000008000000000UL
+#define BIT40 0x0000010000000000UL
+#define BIT41 0x0000020000000000UL
+#define BIT42 0x0000040000000000UL
+#define BIT43 0x0000080000000000UL
+#define BIT44 0x0000100000000000UL
+#define BIT45 0x0000200000000000UL
+#define BIT46 0x0000400000000000UL
+#define BIT47 0x0000800000000000UL
+#define BIT48 0x0001000000000000UL
+#define BIT49 0x0002000000000000UL
+#define BIT50 0x0004000000000000UL
+#define BIT51 0x0008000000000000UL
+#define BIT52 0x0010000000000000UL
+#define BIT53 0x0020000000000000UL
+#define BIT54 0x0040000000000000UL
+#define BIT55 0x0080000000000000UL
+#define BIT56 0x0100000000000000UL
+#define BIT57 0x0200000000000000UL
+#define BIT58 0x0400000000000000UL
+#define BIT59 0x0800000000000000UL
+#define BIT60 0x1000000000000000UL
+#define BIT61 0x2000000000000000UL
+#define BIT62 0x4000000000000000UL
+#define BIT63 0x8000000000000000UL
+
+//
+// Support for variable length argument lists using the ANSI standard.
+//
+// Since we are using the ANSI standard we used the standard nameing and
+// did not folow the coding convention
+//
+// VA_LIST - typedef for argument list.
+// VA_START (VA_LIST Marker, argument before the ...) - Init Marker for use.
+// VA_END (VA_LIST Marker) - Clear Marker
+// VA_ARG (VA_LIST Marker, var arg size) - Use Marker to get an argumnet from
+// the ... list. You must know the size and pass it in this macro.
+//
+// example:
+//
+// UINTN
+// ExampleVarArg (
+// IN UINTN NumberOfArgs,
+// ...
+// )
+// {
+// VA_LIST Marker;
+// UINTN Index;
+// UINTN Result;
+//
+// //
+// // Initialize the Marker
+// //
+// VA_START (Marker, NumberOfArgs);
+// for (Index = 0, Result = 0; Index < NumberOfArgs; Index++) {
+// //
+// // The ... list is a series of UINTN values, so average them up.
+// //
+// Result += VA_ARG (Marker, UINTN);
+// }
+//
+// VA_END (Marker);
+// return Result
+// }
+//
+
+#define _INT_SIZE_OF(n) ((sizeof (n) + sizeof (UINTN) - 1) &~(sizeof (UINTN) - 1))
+
+//
+// Also support coding convention rules for var arg macros
+//
+#ifndef VA_START
+
+typedef CHAR8 *VA_LIST;
+#define VA_START(ap, v) (ap = (VA_LIST) & (v) + _INT_SIZE_OF (v))
+#define VA_ARG(ap, t) (*(t *) ((ap += _INT_SIZE_OF (t)) - _INT_SIZE_OF (t)))
+#define VA_END(ap) (ap = (VA_LIST) 0)
+
+#endif
+
+//
+// Macro that returns the byte offset of a field in a data structure.
+//
+#define OFFSET_OF(TYPE, Field) ((UINTN) &(((TYPE *)0)->Field))
+
+///
+/// CONTAINING_RECORD - returns a pointer to the structure
+/// from one of it's elements.
+///
+#define _CR(Record, TYPE, Field) ((TYPE *) ((CHAR8 *) (Record) - (CHAR8 *) &(((TYPE *) 0)->Field)))
+
+///
+/// ALIGN_POINTER - aligns a pointer to the lowest boundry
+///
+#define ALIGN_POINTER(p, s) ((VOID *) ((UINTN)(p) + (((s) - ((UINTN) (p))) & ((s) - 1))))
+
+///
+/// ALIGN_VARIABLE - aligns a variable up to the next natural boundry for int size of a processor
+///
+#define ALIGN_VARIABLE(Value, Adjustment) \
+ Adjustment = 0U; \
+ if ((UINTN) (Value) % sizeof (UINTN)) { \
+ (Adjustment) = (UINTN)(sizeof (UINTN) - ((UINTN) (Value) % sizeof (UINTN))); \
+ } \
+ (Value) = (UINTN)((UINTN) (Value) + (UINTN) (Adjustment))
+
+//
+// Return the maximum of two operands.
+// This macro returns the maximum of two operand specified by a and b.
+// Both a and b must be the same numerical types, signed or unsigned.
+//
+#define MAX(a, b) \
+ (((a) > (b)) ? (a) : (b))
+
+
+//
+// Return the minimum of two operands.
+// This macro returns the minimal of two operand specified by a and b.
+// Both a and b must be the same numerical types, signed or unsigned.
+//
+#define MIN(a, b) \
+ (((a) < (b)) ? (a) : (b))
+
+
+//
+// EFI Error Codes common to all execution phases
+//
+
+typedef INTN RETURN_STATUS;
+
+///
+/// Set the upper bit to indicate EFI Error.
+///
+#define ENCODE_ERROR(a) (MAX_BIT | (a))
+
+#define ENCODE_WARNING(a) (a)
+#define RETURN_ERROR(a) ((INTN) (a) < 0)
+
+#define RETURN_SUCCESS 0
+#define RETURN_LOAD_ERROR ENCODE_ERROR (1)
+#define RETURN_INVALID_PARAMETER ENCODE_ERROR (2)
+#define RETURN_UNSUPPORTED ENCODE_ERROR (3)
+#define RETURN_BAD_BUFFER_SIZE ENCODE_ERROR (4)
+#define RETURN_BUFFER_TOO_SMALL ENCODE_ERROR (5)
+#define RETURN_NOT_READY ENCODE_ERROR (6)
+#define RETURN_DEVICE_ERROR ENCODE_ERROR (7)
+#define RETURN_WRITE_PROTECTED ENCODE_ERROR (8)
+#define RETURN_OUT_OF_RESOURCES ENCODE_ERROR (9)
+#define RETURN_VOLUME_CORRUPTED ENCODE_ERROR (10)
+#define RETURN_VOLUME_FULL ENCODE_ERROR (11)
+#define RETURN_NO_MEDIA ENCODE_ERROR (12)
+#define RETURN_MEDIA_CHANGED ENCODE_ERROR (13)
+#define RETURN_NOT_FOUND ENCODE_ERROR (14)
+#define RETURN_ACCESS_DENIED ENCODE_ERROR (15)
+#define RETURN_NO_RESPONSE ENCODE_ERROR (16)
+#define RETURN_NO_MAPPING ENCODE_ERROR (17)
+#define RETURN_TIMEOUT ENCODE_ERROR (18)
+#define RETURN_NOT_STARTED ENCODE_ERROR (19)
+#define RETURN_ALREADY_STARTED ENCODE_ERROR (20)
+#define RETURN_ABORTED ENCODE_ERROR (21)
+#define RETURN_ICMP_ERROR ENCODE_ERROR (22)
+#define RETURN_TFTP_ERROR ENCODE_ERROR (23)
+#define RETURN_PROTOCOL_ERROR ENCODE_ERROR (24)
+#define RETURN_INCOMPATIBLE_VERSION ENCODE_ERROR (25)
+#define RETURN_SECURITY_VIOLATION ENCODE_ERROR (26)
+#define RETURN_CRC_ERROR ENCODE_ERROR (27)
+#define RETURN_END_OF_MEDIA ENCODE_ERROR (28)
+#define RETURN_END_OF_FILE ENCODE_ERROR (31)
+#define RETURN_INVALID_LANGUAGE ENCODE_ERROR (32)
+
+
+#define RETURN_WARN_UNKNOWN_GLYPH ENCODE_WARNING (1)
+#define RETURN_WARN_DELETE_FAILURE ENCODE_WARNING (2)
+#define RETURN_WARN_WRITE_FAILURE ENCODE_WARNING (3)
+#define RETURN_WARN_BUFFER_TOO_SMALL ENCODE_WARNING (4)
+
+#endif
+
diff --git a/gpxe/src/include/gpxe/efi/Guid/PcAnsi.h b/gpxe/src/include/gpxe/efi/Guid/PcAnsi.h
new file mode 100644
index 00000000..1dab3109
--- /dev/null
+++ b/gpxe/src/include/gpxe/efi/Guid/PcAnsi.h
@@ -0,0 +1,58 @@
+/** @file
+ Terminal Device Path Vendor Guid.
+
+ Copyright (c) 2006, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+ @par Revision Reference:
+ GUIDs defined in UEFI 2.0 spec.
+
+**/
+
+#ifndef __PC_ANSI_H__
+#define __PC_ANSI_H__
+
+#define EFI_PC_ANSI_GUID \
+ { \
+ 0xe0c14753, 0xf9be, 0x11d2, {0x9a, 0x0c, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d } \
+ }
+
+#define EFI_VT_100_GUID \
+ { \
+ 0xdfa66065, 0xb419, 0x11d3, {0x9a, 0x2d, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d } \
+ }
+
+#define EFI_VT_100_PLUS_GUID \
+ { \
+ 0x7baec70b, 0x57e0, 0x4c76, {0x8e, 0x87, 0x2f, 0x9e, 0x28, 0x08, 0x83, 0x43 } \
+ }
+
+#define EFI_VT_UTF8_GUID \
+ { \
+ 0xad15a0d6, 0x8bec, 0x4acf, {0xa0, 0x73, 0xd0, 0x1d, 0xe7, 0x7e, 0x2d, 0x88 } \
+ }
+
+#define EFI_UART_DEVICE_PATH_GUID \
+ { \
+ 0x37499a9d, 0x542f, 0x4c89, {0xa0, 0x26, 0x35, 0xda, 0x14, 0x20, 0x94, 0xe4 } \
+ }
+
+#define EFI_SAS_DEVICE_PATH_GUID \
+ { \
+ 0xd487ddb4, 0x008b, 0x11d9, {0xaf, 0xdc, 0x00, 0x10, 0x83, 0xff, 0xca, 0x4d } \
+ }
+
+extern EFI_GUID gEfiPcAnsiGuid;
+extern EFI_GUID gEfiVT100Guid;
+extern EFI_GUID gEfiVT100PlusGuid;
+extern EFI_GUID gEfiVTUTF8Guid;
+extern EFI_GUID gEfiUartDevicePathGuid;
+extern EFI_GUID gEfiSasDevicePathGuid;
+
+#endif
diff --git a/gpxe/src/include/gpxe/efi/Ia32/ProcessorBind.h b/gpxe/src/include/gpxe/efi/Ia32/ProcessorBind.h
new file mode 100644
index 00000000..512564ca
--- /dev/null
+++ b/gpxe/src/include/gpxe/efi/Ia32/ProcessorBind.h
@@ -0,0 +1,221 @@
+/** @file
+ Processor or Compiler specific defines and types for Ia32 architecture.
+
+ Copyright (c) 2006, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __PROCESSOR_BIND_H__
+#define __PROCESSOR_BIND_H__
+
+///
+/// Define the processor type so other code can make processor based choices
+///
+#define MDE_CPU_IA32
+
+//
+// Make sure we are useing the correct packing rules per EFI specification
+//
+#ifndef __GNUC__
+#pragma pack()
+#endif
+
+#if __INTEL_COMPILER
+//
+// Disable ICC's remark #593: "LocalVariable" was set but never used
+// This is legal ANSI C code so we disable the remark that is turned on with -Wall
+//
+#pragma warning ( disable : 593 )
+
+//
+// Disable ICC's remark #869: "Parameter" was never referenced warning.
+// This is legal ANSI C code so we disable the remark that is turned on with -Wall
+//
+#pragma warning ( disable : 869 )
+
+//
+// Disable ICC's remark #1418: external function definition with no prior declaration.
+// This is legal ANSI C code so we disable the remark that is turned on with /W4
+//
+#pragma warning ( disable : 1418 )
+
+//
+// Disable ICC's remark #1419: external declaration in primary source file
+// This is legal ANSI C code so we disable the remark that is turned on with /W4
+//
+#pragma warning ( disable : 1419 )
+
+#endif
+
+
+#if _MSC_EXTENSIONS
+
+//
+// Disable warning that make it impossible to compile at /W4
+// This only works for Microsoft* tools
+//
+
+//
+// Disabling bitfield type checking warnings.
+//
+#pragma warning ( disable : 4214 )
+
+//
+// Disabling the unreferenced formal parameter warnings.
+//
+#pragma warning ( disable : 4100 )
+
+//
+// Disable slightly different base types warning as CHAR8 * can not be set
+// to a constant string.
+//
+#pragma warning ( disable : 4057 )
+
+//
+// ASSERT(FALSE) or while (TRUE) are legal constructes so supress this warning
+//
+#pragma warning ( disable : 4127 )
+
+//
+// This warning is caused by functions defined but not used. For precompiled header only.
+//
+#pragma warning ( disable : 4505 )
+
+//
+// This warning is caused by empty (after preprocessing) souce file. For precompiled header only.
+//
+#pragma warning ( disable : 4206 )
+
+#endif
+
+
+#if !defined(__GNUC__) && (__STDC_VERSION__ < 199901L)
+ //
+ // No ANSI C 2000 stdint.h integer width declarations, so define equivalents
+ //
+
+ #if _MSC_EXTENSIONS
+
+ //
+ // use Microsoft* C complier dependent interger width types
+ //
+ typedef unsigned __int64 UINT64;
+ typedef __int64 INT64;
+ typedef unsigned __int32 UINT32;
+ typedef __int32 INT32;
+ typedef unsigned short UINT16;
+ typedef unsigned short CHAR16;
+ typedef short INT16;
+ typedef unsigned char BOOLEAN;
+ typedef unsigned char UINT8;
+ typedef char CHAR8;
+ typedef char INT8;
+ #else
+
+ //
+ // Assume standard IA-32 alignment.
+ // Need to check portability of long long
+ //
+ typedef unsigned long long UINT64;
+ typedef long long INT64;
+ typedef unsigned int UINT32;
+ typedef int INT32;
+ typedef unsigned short UINT16;
+ typedef unsigned short CHAR16;
+ typedef short INT16;
+ typedef unsigned char BOOLEAN;
+ typedef unsigned char UINT8;
+ typedef char CHAR8;
+ typedef char INT8;
+ #endif
+
+ #define UINT8_MAX 0xff
+
+#else
+ //
+ // Use ANSI C 2000 stdint.h integer width declarations
+ //
+ #include "stdint.h"
+ typedef uint8_t BOOLEAN;
+ typedef int8_t INT8;
+ typedef uint8_t UINT8;
+ typedef int16_t INT16;
+ typedef uint16_t UINT16;
+ typedef int32_t INT32;
+ typedef uint32_t UINT32;
+ typedef int64_t INT64;
+ typedef uint64_t UINT64;
+ typedef char CHAR8;
+ typedef uint16_t CHAR16;
+
+#endif
+
+typedef UINT32 UINTN;
+typedef INT32 INTN;
+
+
+///
+/// Processor specific defines
+///
+#define MAX_BIT 0x80000000
+#define MAX_2_BITS 0xC0000000
+
+///
+/// Maximum legal IA-32 address
+///
+#define MAX_ADDRESS 0xFFFFFFFF
+
+///
+/// The stack alignment required for IA-32
+///
+#define CPU_STACK_ALIGNMENT sizeof(UINTN)
+
+//
+// Modifier to ensure that all protocol member functions and EFI intrinsics
+// use the correct C calling convention. All protocol member functions and
+// EFI intrinsics are required to modify thier member functions with EFIAPI.
+//
+#if _MSC_EXTENSIONS
+ ///
+ /// Microsoft* compiler requires _EFIAPI useage, __cdecl is Microsoft* specific C.
+ ///
+ #define EFIAPI __cdecl
+#else
+ #if __GNUC__
+ #define EFIAPI __attribute__((cdecl,regparm(0)))
+ #endif
+#endif
+
+//
+// The Microsoft* C compiler can removed references to unreferenced data items
+// if the /OPT:REF linker option is used. We defined a macro as this is a
+// a non standard extension
+//
+#if _MSC_EXTENSIONS
+ #define GLOBAL_REMOVE_IF_UNREFERENCED __declspec(selectany)
+#else
+ #define GLOBAL_REMOVE_IF_UNREFERENCED
+#endif
+
+//
+// For symbol name in GNU assembly code, an extra "_" is necessary
+//
+#if __GNUC__
+ #if defined(linux)
+ #define ASM_PFX(name) name
+ #else
+ #define ASM_PFX(name) _##name
+ #endif
+#endif
+
+#define FUNCTION_ENTRY_POINT(p) (p)
+
+#endif
+
diff --git a/gpxe/src/include/gpxe/efi/IndustryStandard/PeImage.h b/gpxe/src/include/gpxe/efi/IndustryStandard/PeImage.h
new file mode 100644
index 00000000..666d4ec3
--- /dev/null
+++ b/gpxe/src/include/gpxe/efi/IndustryStandard/PeImage.h
@@ -0,0 +1,742 @@
+/** @file
+ EFI image format for PE32 and PE32+. Please note some data structures are
+ different for PE32 and PE32+. EFI_IMAGE_NT_HEADERS32 is for PE32 and
+ EFI_IMAGE_NT_HEADERS64 is for PE32+.
+
+ This file is coded to the Visual Studio, Microsoft Portable Executable and
+ Common Object File Format Specification, Revision 8.0 - May 16, 2006.
+
+ Copyright (c) 2006 - 2007, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __EFI_IMAGE_H__
+#define __EFI_IMAGE_H__
+
+//
+// PE32+ Subsystem type for EFI images
+//
+#define EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION 10
+#define EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER 11
+#define EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER 12
+#define EFI_IMAGE_SUBSYSTEM_EFI_EFI_ROM 13
+
+#define EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER 13
+
+
+//
+// PE32+ Machine type for EFI images
+//
+#define IMAGE_FILE_MACHINE_I386 0x014c
+#define IMAGE_FILE_MACHINE_IA64 0x0200
+#define IMAGE_FILE_MACHINE_EBC 0x0EBC
+#define IMAGE_FILE_MACHINE_X64 0x8664
+//
+// Support old names for backward compatible
+//
+#define EFI_IMAGE_MACHINE_IA32 IMAGE_FILE_MACHINE_I386
+#define EFI_IMAGE_MACHINE_IA64 IMAGE_FILE_MACHINE_IA64
+#define EFI_IMAGE_MACHINE_IPF IMAGE_FILE_MACHINE_IA64
+#define EFI_IMAGE_MACHINE_EBC IMAGE_FILE_MACHINE_EBC
+#define EFI_IMAGE_MACHINE_X64 IMAGE_FILE_MACHINE_X64
+
+#define EFI_IMAGE_DOS_SIGNATURE 0x5A4D // MZ
+#define EFI_IMAGE_OS2_SIGNATURE 0x454E // NE
+#define EFI_IMAGE_OS2_SIGNATURE_LE 0x454C // LE
+#define EFI_IMAGE_NT_SIGNATURE 0x00004550 // PE00
+
+///
+/// PE images can start with an optional DOS header, so if an image is run
+/// under DOS it can print an error message.
+///
+typedef struct {
+ UINT16 e_magic; // Magic number
+ UINT16 e_cblp; // Bytes on last page of file
+ UINT16 e_cp; // Pages in file
+ UINT16 e_crlc; // Relocations
+ UINT16 e_cparhdr; // Size of header in paragraphs
+ UINT16 e_minalloc; // Minimum extra paragraphs needed
+ UINT16 e_maxalloc; // Maximum extra paragraphs needed
+ UINT16 e_ss; // Initial (relative) SS value
+ UINT16 e_sp; // Initial SP value
+ UINT16 e_csum; // Checksum
+ UINT16 e_ip; // Initial IP value
+ UINT16 e_cs; // Initial (relative) CS value
+ UINT16 e_lfarlc; // File address of relocation table
+ UINT16 e_ovno; // Overlay number
+ UINT16 e_res[4]; // Reserved words
+ UINT16 e_oemid; // OEM identifier (for e_oeminfo)
+ UINT16 e_oeminfo; // OEM information; e_oemid specific
+ UINT16 e_res2[10]; // Reserved words
+ UINT32 e_lfanew; // File address of new exe header
+} EFI_IMAGE_DOS_HEADER;
+
+///
+/// File header format.
+///
+typedef struct {
+ UINT16 Machine;
+ UINT16 NumberOfSections;
+ UINT32 TimeDateStamp;
+ UINT32 PointerToSymbolTable;
+ UINT32 NumberOfSymbols;
+ UINT16 SizeOfOptionalHeader;
+ UINT16 Characteristics;
+} EFI_IMAGE_FILE_HEADER;
+
+#define EFI_IMAGE_SIZEOF_FILE_HEADER 20
+
+#define EFI_IMAGE_FILE_RELOCS_STRIPPED 0x0001 // Relocation info stripped from file.
+#define EFI_IMAGE_FILE_EXECUTABLE_IMAGE 0x0002 // File is executable (i.e. no unresolved externel references).
+#define EFI_IMAGE_FILE_LINE_NUMS_STRIPPED 0x0004 // Line nunbers stripped from file.
+#define EFI_IMAGE_FILE_LOCAL_SYMS_STRIPPED 0x0008 // Local symbols stripped from file.
+#define EFI_IMAGE_FILE_BYTES_REVERSED_LO 0x0080 // Bytes of machine word are reversed.
+#define EFI_IMAGE_FILE_32BIT_MACHINE 0x0100 // 32 bit word machine.
+#define EFI_IMAGE_FILE_DEBUG_STRIPPED 0x0200 // Debugging info stripped from file in .DBG file
+#define EFI_IMAGE_FILE_SYSTEM 0x1000 // System File.
+#define EFI_IMAGE_FILE_DLL 0x2000 // File is a DLL.
+#define EFI_IMAGE_FILE_BYTES_REVERSED_HI 0x8000 // Bytes of machine word are reversed.
+#define EFI_IMAGE_FILE_MACHINE_UNKNOWN 0
+#define EFI_IMAGE_FILE_MACHINE_I386 0x14c // Intel 386.
+#define EFI_IMAGE_FILE_MACHINE_R3000 0x162 // MIPS* little-endian, 0540 big-endian
+#define EFI_IMAGE_FILE_MACHINE_R4000 0x166 // MIPS* little-endian
+#define EFI_IMAGE_FILE_MACHINE_ALPHA 0x184 // Alpha_AXP*
+#define EFI_IMAGE_FILE_MACHINE_POWERPC 0x1F0 // IBM* PowerPC Little-Endian
+#define EFI_IMAGE_FILE_MACHINE_TAHOE 0x7cc // Intel EM machine
+//
+// * Other names and brands may be claimed as the property of others.
+//
+
+///
+/// Directory format.
+///
+typedef struct {
+ UINT32 VirtualAddress;
+ UINT32 Size;
+} EFI_IMAGE_DATA_DIRECTORY;
+
+#define EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES 16
+
+typedef struct {
+ UINT16 Magic;
+ UINT8 MajorLinkerVersion;
+ UINT8 MinorLinkerVersion;
+ UINT32 SizeOfCode;
+ UINT32 SizeOfInitializedData;
+ UINT32 SizeOfUninitializedData;
+ UINT32 AddressOfEntryPoint;
+ UINT32 BaseOfCode;
+ UINT32 BaseOfData;
+ UINT32 BaseOfBss;
+ UINT32 GprMask;
+ UINT32 CprMask[4];
+ UINT32 GpValue;
+} EFI_IMAGE_ROM_OPTIONAL_HEADER;
+
+#define EFI_IMAGE_ROM_OPTIONAL_HDR_MAGIC 0x107
+#define EFI_IMAGE_SIZEOF_ROM_OPTIONAL_HEADER sizeof (EFI_IMAGE_ROM_OPTIONAL_HEADER)
+
+typedef struct {
+ EFI_IMAGE_FILE_HEADER FileHeader;
+ EFI_IMAGE_ROM_OPTIONAL_HEADER OptionalHeader;
+} EFI_IMAGE_ROM_HEADERS;
+
+///
+/// @attention
+/// EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC means PE32 and
+/// EFI_IMAGE_OPTIONAL_HEADER32 must be used. The data structures only vary
+/// after NT additional fields.
+///
+#define EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x10b
+
+typedef struct {
+ ///
+ /// Standard fields.
+ ///
+ UINT16 Magic;
+ UINT8 MajorLinkerVersion;
+ UINT8 MinorLinkerVersion;
+ UINT32 SizeOfCode;
+ UINT32 SizeOfInitializedData;
+ UINT32 SizeOfUninitializedData;
+ UINT32 AddressOfEntryPoint;
+ UINT32 BaseOfCode;
+ UINT32 BaseOfData;
+ ///
+ /// NT additional fields.
+ ///
+ UINT32 ImageBase;
+ UINT32 SectionAlignment;
+ UINT32 FileAlignment;
+ UINT16 MajorOperatingSystemVersion;
+ UINT16 MinorOperatingSystemVersion;
+ UINT16 MajorImageVersion;
+ UINT16 MinorImageVersion;
+ UINT16 MajorSubsystemVersion;
+ UINT16 MinorSubsystemVersion;
+ UINT32 Win32VersionValue;
+ UINT32 SizeOfImage;
+ UINT32 SizeOfHeaders;
+ UINT32 CheckSum;
+ UINT16 Subsystem;
+ UINT16 DllCharacteristics;
+ UINT32 SizeOfStackReserve;
+ UINT32 SizeOfStackCommit;
+ UINT32 SizeOfHeapReserve;
+ UINT32 SizeOfHeapCommit;
+ UINT32 LoaderFlags;
+ UINT32 NumberOfRvaAndSizes;
+ EFI_IMAGE_DATA_DIRECTORY DataDirectory[EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES];
+} EFI_IMAGE_OPTIONAL_HEADER32;
+
+///
+/// @attention
+/// EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC means PE32+ and
+/// EFI_IMAGE_OPTIONAL_HEADER64 must be used. The data structures only vary
+/// after NT additional fields.
+///
+#define EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x20b
+
+typedef struct {
+ //
+ // Standard fields.
+ //
+ UINT16 Magic;
+ UINT8 MajorLinkerVersion;
+ UINT8 MinorLinkerVersion;
+ UINT32 SizeOfCode;
+ UINT32 SizeOfInitializedData;
+ UINT32 SizeOfUninitializedData;
+ UINT32 AddressOfEntryPoint;
+ UINT32 BaseOfCode;
+ //
+ // NT additional fields.
+ //
+ UINT64 ImageBase;
+ UINT32 SectionAlignment;
+ UINT32 FileAlignment;
+ UINT16 MajorOperatingSystemVersion;
+ UINT16 MinorOperatingSystemVersion;
+ UINT16 MajorImageVersion;
+ UINT16 MinorImageVersion;
+ UINT16 MajorSubsystemVersion;
+ UINT16 MinorSubsystemVersion;
+ UINT32 Win32VersionValue;
+ UINT32 SizeOfImage;
+ UINT32 SizeOfHeaders;
+ UINT32 CheckSum;
+ UINT16 Subsystem;
+ UINT16 DllCharacteristics;
+ UINT64 SizeOfStackReserve;
+ UINT64 SizeOfStackCommit;
+ UINT64 SizeOfHeapReserve;
+ UINT64 SizeOfHeapCommit;
+ UINT32 LoaderFlags;
+ UINT32 NumberOfRvaAndSizes;
+ EFI_IMAGE_DATA_DIRECTORY DataDirectory[EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES];
+} EFI_IMAGE_OPTIONAL_HEADER64;
+
+
+///
+/// @attention
+/// EFI_IMAGE_NT_HEADERS32 and EFI_IMAGE_HEADERS64 are for use ONLY
+/// by tools. All proper EFI code MUST use EFI_IMAGE_NT_HEADERS ONLY!!!
+///
+typedef struct {
+ UINT32 Signature;
+ EFI_IMAGE_FILE_HEADER FileHeader;
+ EFI_IMAGE_OPTIONAL_HEADER32 OptionalHeader;
+} EFI_IMAGE_NT_HEADERS32;
+
+#define EFI_IMAGE_SIZEOF_NT_OPTIONAL32_HEADER sizeof (EFI_IMAGE_NT_HEADERS32)
+
+typedef struct {
+ UINT32 Signature;
+ EFI_IMAGE_FILE_HEADER FileHeader;
+ EFI_IMAGE_OPTIONAL_HEADER64 OptionalHeader;
+} EFI_IMAGE_NT_HEADERS64;
+
+#define EFI_IMAGE_SIZEOF_NT_OPTIONAL64_HEADER sizeof (EFI_IMAGE_NT_HEADERS64)
+
+
+//
+// Processor specific definition of EFI_IMAGE_OPTIONAL_HEADER so the
+// type name EFI_IMAGE_OPTIONAL_HEADER is appropriate to the build. Same for
+// EFI_IMAGE_NT_HEADERS. These definitions MUST be used by ALL EFI code.
+//
+#if defined (MDE_CPU_IA32)
+
+#define EFI_IMAGE_MACHINE_TYPE_SUPPORTED(Machine) \
+ (((Machine) == EFI_IMAGE_MACHINE_IA32) || ((Machine) == EFI_IMAGE_MACHINE_EBC))
+
+#define EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED(Machine) ((Machine) == EFI_IMAGE_MACHINE_X64)
+
+//
+// @bug - Remove me when other package updated.
+//
+typedef EFI_IMAGE_NT_HEADERS32 EFI_IMAGE_NT_HEADERS;
+
+#elif defined (MDE_CPU_IPF)
+
+#define EFI_IMAGE_MACHINE_TYPE_SUPPORTED(Machine) \
+ (((Machine) == EFI_IMAGE_MACHINE_IPF) || ((Machine) == EFI_IMAGE_MACHINE_EBC))
+
+#define EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED(Machine) (FALSE)
+
+//
+// @bug - Remove me when other package updated.
+//
+typedef EFI_IMAGE_NT_HEADERS64 EFI_IMAGE_NT_HEADERS;
+
+#elif defined (MDE_CPU_X64)
+
+#define EFI_IMAGE_MACHINE_TYPE_SUPPORTED(Machine) \
+ (((Machine) == EFI_IMAGE_MACHINE_X64) || ((Machine) == EFI_IMAGE_MACHINE_EBC))
+
+#define EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED(Machine) ((Machine) == EFI_IMAGE_MACHINE_IA32)
+
+//
+// @bug - Remove me when other package updated.
+//
+typedef EFI_IMAGE_NT_HEADERS64 EFI_IMAGE_NT_HEADERS;
+
+#elif defined (MDE_CPU_EBC)
+
+///
+/// This is just to make sure you can cross compile with the EBC compiiler.
+/// It does not make sense to have a PE loader coded in EBC. You need to
+/// understand the basic
+///
+#define EFI_IMAGE_MACHINE_TYPE_SUPPORTED(Machine) ((Machine) == EFI_IMAGE_MACHINE_EBC)
+
+#define EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED(Machine) (FALSE)
+
+//
+// @bug - Remove me when other package updated.
+//
+typedef EFI_IMAGE_NT_HEADERS64 EFI_IMAGE_NT_HEADERS;
+
+#else
+#error Unknown Processor Type
+#endif
+
+
+#define EFI_IMAGE_FIRST_SECTION(ntheader) \
+ ( \
+ (EFI_IMAGE_SECTION_HEADER *) \
+ ( \
+ (UINT32) ntheader + \
+ FIELD_OFFSET (EFI_IMAGE_NT_HEADERS, OptionalHeader) + \
+ ((EFI_IMAGE_NT_HEADERS *) (ntheader))->FileHeader.SizeOfOptionalHeader \
+ ) \
+ )
+
+//
+// Subsystem Values
+//
+#define EFI_IMAGE_SUBSYSTEM_UNKNOWN 0
+#define EFI_IMAGE_SUBSYSTEM_NATIVE 1
+#define EFI_IMAGE_SUBSYSTEM_WINDOWS_GUI 2
+#define EFI_IMAGE_SUBSYSTEM_WINDOWS_CUI 3.
+#define EFI_IMAGE_SUBSYSTEM_OS2_CUI 5
+#define EFI_IMAGE_SUBSYSTEM_POSIX_CUI 7
+
+//
+// Directory Entries
+//
+#define EFI_IMAGE_DIRECTORY_ENTRY_EXPORT 0
+#define EFI_IMAGE_DIRECTORY_ENTRY_IMPORT 1
+#define EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE 2
+#define EFI_IMAGE_DIRECTORY_ENTRY_EXCEPTION 3
+#define EFI_IMAGE_DIRECTORY_ENTRY_SECURITY 4
+#define EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC 5
+#define EFI_IMAGE_DIRECTORY_ENTRY_DEBUG 6
+#define EFI_IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7
+#define EFI_IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8
+#define EFI_IMAGE_DIRECTORY_ENTRY_TLS 9
+#define EFI_IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10
+
+//
+// Section header format.
+//
+#define EFI_IMAGE_SIZEOF_SHORT_NAME 8
+
+typedef struct {
+ UINT8 Name[EFI_IMAGE_SIZEOF_SHORT_NAME];
+ union {
+ UINT32 PhysicalAddress;
+ UINT32 VirtualSize;
+ } Misc;
+ UINT32 VirtualAddress;
+ UINT32 SizeOfRawData;
+ UINT32 PointerToRawData;
+ UINT32 PointerToRelocations;
+ UINT32 PointerToLinenumbers;
+ UINT16 NumberOfRelocations;
+ UINT16 NumberOfLinenumbers;
+ UINT32 Characteristics;
+} EFI_IMAGE_SECTION_HEADER;
+
+#define EFI_IMAGE_SIZEOF_SECTION_HEADER 40
+
+#define EFI_IMAGE_SCN_TYPE_NO_PAD 0x00000008 // Reserved.
+#define EFI_IMAGE_SCN_CNT_CODE 0x00000020
+#define EFI_IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040
+#define EFI_IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080
+
+#define EFI_IMAGE_SCN_LNK_OTHER 0x00000100 // Reserved.
+#define EFI_IMAGE_SCN_LNK_INFO 0x00000200 // Section contains comments or some other type of information.
+#define EFI_IMAGE_SCN_LNK_REMOVE 0x00000800 // Section contents will not become part of image.
+#define EFI_IMAGE_SCN_LNK_COMDAT 0x00001000
+
+#define EFI_IMAGE_SCN_ALIGN_1BYTES 0x00100000
+#define EFI_IMAGE_SCN_ALIGN_2BYTES 0x00200000
+#define EFI_IMAGE_SCN_ALIGN_4BYTES 0x00300000
+#define EFI_IMAGE_SCN_ALIGN_8BYTES 0x00400000
+#define EFI_IMAGE_SCN_ALIGN_16BYTES 0x00500000
+#define EFI_IMAGE_SCN_ALIGN_32BYTES 0x00600000
+#define EFI_IMAGE_SCN_ALIGN_64BYTES 0x00700000
+
+#define EFI_IMAGE_SCN_MEM_DISCARDABLE 0x02000000
+#define EFI_IMAGE_SCN_MEM_NOT_CACHED 0x04000000
+#define EFI_IMAGE_SCN_MEM_NOT_PAGED 0x08000000
+#define EFI_IMAGE_SCN_MEM_SHARED 0x10000000
+#define EFI_IMAGE_SCN_MEM_EXECUTE 0x20000000
+#define EFI_IMAGE_SCN_MEM_READ 0x40000000
+#define EFI_IMAGE_SCN_MEM_WRITE 0x80000000
+
+///
+/// Symbol format.
+///
+#define EFI_IMAGE_SIZEOF_SYMBOL 18
+
+//
+// Section values.
+//
+// Symbols have a section number of the section in which they are
+// defined. Otherwise, section numbers have the following meanings:
+//
+#define EFI_IMAGE_SYM_UNDEFINED (UINT16) 0 // Symbol is undefined or is common.
+#define EFI_IMAGE_SYM_ABSOLUTE (UINT16) -1 // Symbol is an absolute value.
+#define EFI_IMAGE_SYM_DEBUG (UINT16) -2 // Symbol is a special debug item.
+//
+// Type (fundamental) values.
+//
+#define EFI_IMAGE_SYM_TYPE_NULL 0 // no type.
+#define EFI_IMAGE_SYM_TYPE_VOID 1 //
+#define EFI_IMAGE_SYM_TYPE_CHAR 2 // type character.
+#define EFI_IMAGE_SYM_TYPE_SHORT 3 // type short integer.
+#define EFI_IMAGE_SYM_TYPE_INT 4
+#define EFI_IMAGE_SYM_TYPE_LONG 5
+#define EFI_IMAGE_SYM_TYPE_FLOAT 6
+#define EFI_IMAGE_SYM_TYPE_DOUBLE 7
+#define EFI_IMAGE_SYM_TYPE_STRUCT 8
+#define EFI_IMAGE_SYM_TYPE_UNION 9
+#define EFI_IMAGE_SYM_TYPE_ENUM 10 // enumeration.
+#define EFI_IMAGE_SYM_TYPE_MOE 11 // member of enumeration.
+#define EFI_IMAGE_SYM_TYPE_BYTE 12
+#define EFI_IMAGE_SYM_TYPE_WORD 13
+#define EFI_IMAGE_SYM_TYPE_UINT 14
+#define EFI_IMAGE_SYM_TYPE_DWORD 15
+
+//
+// Type (derived) values.
+//
+#define EFI_IMAGE_SYM_DTYPE_NULL 0 // no derived type.
+#define EFI_IMAGE_SYM_DTYPE_POINTER 1
+#define EFI_IMAGE_SYM_DTYPE_FUNCTION 2
+#define EFI_IMAGE_SYM_DTYPE_ARRAY 3
+
+//
+// Storage classes.
+//
+#define EFI_IMAGE_SYM_CLASS_END_OF_FUNCTION (UINT8) -1
+#define EFI_IMAGE_SYM_CLASS_NULL 0
+#define EFI_IMAGE_SYM_CLASS_AUTOMATIC 1
+#define EFI_IMAGE_SYM_CLASS_EXTERNAL 2
+#define EFI_IMAGE_SYM_CLASS_STATIC 3
+#define EFI_IMAGE_SYM_CLASS_REGISTER 4
+#define EFI_IMAGE_SYM_CLASS_EXTERNAL_DEF 5
+#define EFI_IMAGE_SYM_CLASS_LABEL 6
+#define EFI_IMAGE_SYM_CLASS_UNDEFINED_LABEL 7
+#define EFI_IMAGE_SYM_CLASS_MEMBER_OF_STRUCT 8
+#define EFI_IMAGE_SYM_CLASS_ARGUMENT 9
+#define EFI_IMAGE_SYM_CLASS_STRUCT_TAG 10
+#define EFI_IMAGE_SYM_CLASS_MEMBER_OF_UNION 11
+#define EFI_IMAGE_SYM_CLASS_UNION_TAG 12
+#define EFI_IMAGE_SYM_CLASS_TYPE_DEFINITION 13
+#define EFI_IMAGE_SYM_CLASS_UNDEFINED_STATIC 14
+#define EFI_IMAGE_SYM_CLASS_ENUM_TAG 15
+#define EFI_IMAGE_SYM_CLASS_MEMBER_OF_ENUM 16
+#define EFI_IMAGE_SYM_CLASS_REGISTER_PARAM 17
+#define EFI_IMAGE_SYM_CLASS_BIT_FIELD 18
+#define EFI_IMAGE_SYM_CLASS_BLOCK 100
+#define EFI_IMAGE_SYM_CLASS_FUNCTION 101
+#define EFI_IMAGE_SYM_CLASS_END_OF_STRUCT 102
+#define EFI_IMAGE_SYM_CLASS_FILE 103
+#define EFI_IMAGE_SYM_CLASS_SECTION 104
+#define EFI_IMAGE_SYM_CLASS_WEAK_EXTERNAL 105
+
+//
+// type packing constants
+//
+#define EFI_IMAGE_N_BTMASK 017
+#define EFI_IMAGE_N_TMASK 060
+#define EFI_IMAGE_N_TMASK1 0300
+#define EFI_IMAGE_N_TMASK2 0360
+#define EFI_IMAGE_N_BTSHFT 4
+#define EFI_IMAGE_N_TSHIFT 2
+
+//
+// Communal selection types.
+//
+#define EFI_IMAGE_COMDAT_SELECT_NODUPLICATES 1
+#define EFI_IMAGE_COMDAT_SELECT_ANY 2
+#define EFI_IMAGE_COMDAT_SELECT_SAME_SIZE 3
+#define EFI_IMAGE_COMDAT_SELECT_EXACT_MATCH 4
+#define EFI_IMAGE_COMDAT_SELECT_ASSOCIATIVE 5
+
+#define EFI_IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY 1
+#define EFI_IMAGE_WEAK_EXTERN_SEARCH_LIBRARY 2
+#define EFI_IMAGE_WEAK_EXTERN_SEARCH_ALIAS 3
+
+///
+/// Relocation format.
+///
+typedef struct {
+ UINT32 VirtualAddress;
+ UINT32 SymbolTableIndex;
+ UINT16 Type;
+} EFI_IMAGE_RELOCATION;
+
+#define EFI_IMAGE_SIZEOF_RELOCATION 10
+
+//
+// I386 relocation types.
+//
+#define EFI_IMAGE_REL_I386_ABSOLUTE 0x0000 // Reference is absolute, no relocation is necessary
+#define EFI_IMAGE_REL_I386_DIR16 0x0001 // Direct 16-bit reference to the symbols virtual address
+#define EFI_IMAGE_REL_I386_REL16 0x0002 // PC-relative 16-bit reference to the symbols virtual address
+#define EFI_IMAGE_REL_I386_DIR32 0x0006 // Direct 32-bit reference to the symbols virtual address
+#define EFI_IMAGE_REL_I386_DIR32NB 0x0007 // Direct 32-bit reference to the symbols virtual address, base not included
+#define EFI_IMAGE_REL_I386_SEG12 0x0009 // Direct 16-bit reference to the segment-selector bits of a 32-bit virtual address
+#define EFI_IMAGE_REL_I386_SECTION 0x001a
+#define EFI_IMAGE_REL_I386_SECREL 0x000b
+#define EFI_IMAGE_REL_I386_REL32 0x0014 // PC-relative 32-bit reference to the symbols virtual address
+
+//
+// x64 processor relocation types.
+//
+#define IMAGE_REL_AMD64_ABSOLUTE 0x0000
+#define IMAGE_REL_AMD64_ADDR64 0x0001
+#define IMAGE_REL_AMD64_ADDR32 0x0002
+#define IMAGE_REL_AMD64_ADDR32NB 0x0003
+#define IMAGE_REL_AMD64_REL32 0x0004
+#define IMAGE_REL_AMD64_REL32_1 0x0005
+#define IMAGE_REL_AMD64_REL32_2 0x0006
+#define IMAGE_REL_AMD64_REL32_3 0x0007
+#define IMAGE_REL_AMD64_REL32_4 0x0008
+#define IMAGE_REL_AMD64_REL32_5 0x0009
+#define IMAGE_REL_AMD64_SECTION 0x000A
+#define IMAGE_REL_AMD64_SECREL 0x000B
+#define IMAGE_REL_AMD64_SECREL7 0x000C
+#define IMAGE_REL_AMD64_TOKEN 0x000D
+#define IMAGE_REL_AMD64_SREL32 0x000E
+#define IMAGE_REL_AMD64_PAIR 0x000F
+#define IMAGE_REL_AMD64_SSPAN32 0x0010
+
+///
+/// Based relocation format.
+///
+typedef struct {
+ UINT32 VirtualAddress;
+ UINT32 SizeOfBlock;
+} EFI_IMAGE_BASE_RELOCATION;
+
+#define EFI_IMAGE_SIZEOF_BASE_RELOCATION 8
+
+//
+// Based relocation types.
+//
+#define EFI_IMAGE_REL_BASED_ABSOLUTE 0
+#define EFI_IMAGE_REL_BASED_HIGH 1
+#define EFI_IMAGE_REL_BASED_LOW 2
+#define EFI_IMAGE_REL_BASED_HIGHLOW 3
+#define EFI_IMAGE_REL_BASED_HIGHADJ 4
+#define EFI_IMAGE_REL_BASED_MIPS_JMPADDR 5
+#define EFI_IMAGE_REL_BASED_IA64_IMM64 9
+#define EFI_IMAGE_REL_BASED_DIR64 10
+
+///
+/// Line number format.
+///
+typedef struct {
+ union {
+ UINT32 SymbolTableIndex; // Symbol table index of function name if Linenumber is 0.
+ UINT32 VirtualAddress; // Virtual address of line number.
+ } Type;
+ UINT16 Linenumber; // Line number.
+} EFI_IMAGE_LINENUMBER;
+
+#define EFI_IMAGE_SIZEOF_LINENUMBER 6
+
+//
+// Archive format.
+//
+#define EFI_IMAGE_ARCHIVE_START_SIZE 8
+#define EFI_IMAGE_ARCHIVE_START "!<arch>\n"
+#define EFI_IMAGE_ARCHIVE_END "`\n"
+#define EFI_IMAGE_ARCHIVE_PAD "\n"
+#define EFI_IMAGE_ARCHIVE_LINKER_MEMBER "/ "
+#define EFI_IMAGE_ARCHIVE_LONGNAMES_MEMBER "// "
+
+typedef struct {
+ UINT8 Name[16]; // File member name - `/' terminated.
+ UINT8 Date[12]; // File member date - decimal.
+ UINT8 UserID[6]; // File member user id - decimal.
+ UINT8 GroupID[6]; // File member group id - decimal.
+ UINT8 Mode[8]; // File member mode - octal.
+ UINT8 Size[10]; // File member size - decimal.
+ UINT8 EndHeader[2]; // String to end header.
+} EFI_IMAGE_ARCHIVE_MEMBER_HEADER;
+
+#define EFI_IMAGE_SIZEOF_ARCHIVE_MEMBER_HDR 60
+
+//
+// DLL support.
+//
+
+///
+/// DLL Export Format
+///
+typedef struct {
+ UINT32 Characteristics;
+ UINT32 TimeDateStamp;
+ UINT16 MajorVersion;
+ UINT16 MinorVersion;
+ UINT32 Name;
+ UINT32 Base;
+ UINT32 NumberOfFunctions;
+ UINT32 NumberOfNames;
+ UINT32 AddressOfFunctions;
+ UINT32 AddressOfNames;
+ UINT32 AddressOfNameOrdinals;
+} EFI_IMAGE_EXPORT_DIRECTORY;
+
+///
+/// DLL support.
+/// Import Format
+///
+typedef struct {
+ UINT16 Hint;
+ UINT8 Name[1];
+} EFI_IMAGE_IMPORT_BY_NAME;
+
+typedef struct {
+ union {
+ UINT32 Function;
+ UINT32 Ordinal;
+ EFI_IMAGE_IMPORT_BY_NAME *AddressOfData;
+ } u1;
+} EFI_IMAGE_THUNK_DATA;
+
+#define EFI_IMAGE_ORDINAL_FLAG 0x80000000
+#define EFI_IMAGE_SNAP_BY_ORDINAL(Ordinal) ((Ordinal & EFI_IMAGE_ORDINAL_FLAG) != 0)
+#define EFI_IMAGE_ORDINAL(Ordinal) (Ordinal & 0xffff)
+
+typedef struct {
+ UINT32 Characteristics;
+ UINT32 TimeDateStamp;
+ UINT32 ForwarderChain;
+ UINT32 Name;
+ EFI_IMAGE_THUNK_DATA *FirstThunk;
+} EFI_IMAGE_IMPORT_DESCRIPTOR;
+
+///
+/// Debug Format
+///
+#define EFI_IMAGE_DEBUG_TYPE_CODEVIEW 2
+
+typedef struct {
+ UINT32 Characteristics;
+ UINT32 TimeDateStamp;
+ UINT16 MajorVersion;
+ UINT16 MinorVersion;
+ UINT32 Type;
+ UINT32 SizeOfData;
+ UINT32 RVA;
+ UINT32 FileOffset;
+} EFI_IMAGE_DEBUG_DIRECTORY_ENTRY;
+
+#define CODEVIEW_SIGNATURE_NB10 0x3031424E // "NB10"
+typedef struct {
+ UINT32 Signature; // "NB10"
+ UINT32 Unknown;
+ UINT32 Unknown2;
+ UINT32 Unknown3;
+ //
+ // Filename of .PDB goes here
+ //
+} EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY;
+
+#define CODEVIEW_SIGNATURE_RSDS 0x53445352 // "RSDS"
+typedef struct {
+ UINT32 Signature; // "RSDS"
+ UINT32 Unknown;
+ UINT32 Unknown2;
+ UINT32 Unknown3;
+ UINT32 Unknown4;
+ UINT32 Unknown5;
+ //
+ // Filename of .PDB goes here
+ //
+} EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY;
+
+///
+/// Header format for TE images
+///
+typedef struct {
+ UINT16 Signature; // signature for TE format = "VZ"
+ UINT16 Machine; // from the original file header
+ UINT8 NumberOfSections; // from the original file header
+ UINT8 Subsystem; // from original optional header
+ UINT16 StrippedSize; // how many bytes we removed from the header
+ UINT32 AddressOfEntryPoint; // offset to entry point -- from original optional header
+ UINT32 BaseOfCode; // from original image -- required for ITP debug
+ UINT64 ImageBase; // from original file header
+ EFI_IMAGE_DATA_DIRECTORY DataDirectory[2]; // only base relocation and debug directory
+} EFI_TE_IMAGE_HEADER;
+
+#define EFI_TE_IMAGE_HEADER_SIGNATURE 0x5A56 // "VZ"
+
+//
+// Data directory indexes in our TE image header
+//
+#define EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC 0
+#define EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG 1
+
+
+///
+/// Union of PE32, PE32+, and TE headers
+///
+typedef union {
+ EFI_IMAGE_NT_HEADERS32 Pe32;
+ EFI_IMAGE_NT_HEADERS64 Pe32Plus;
+ EFI_TE_IMAGE_HEADER Te;
+} EFI_IMAGE_OPTIONAL_HEADER_UNION;
+
+typedef union {
+ EFI_IMAGE_NT_HEADERS32 *Pe32;
+ EFI_IMAGE_NT_HEADERS64 *Pe32Plus;
+ EFI_TE_IMAGE_HEADER *Te;
+ EFI_IMAGE_OPTIONAL_HEADER_UNION *Union;
+} EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION;
+
+#endif
diff --git a/gpxe/src/include/gpxe/efi/LICENCE b/gpxe/src/include/gpxe/efi/LICENCE
new file mode 100644
index 00000000..6aa2b2ff
--- /dev/null
+++ b/gpxe/src/include/gpxe/efi/LICENCE
@@ -0,0 +1,40 @@
+The EFI headers contained herein are copied from the EFI Development
+Kit, available from http://www.tianocore.org and published under the
+following licence:
+
+ BSD License from Intel
+ Copyright (c) 2004, Intel Corporation
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ 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.
+
+ Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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
+ COPYRIGHT OWNER 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.
+
+
+This licence applies only to files that are part of the EFI
+Development Kit. Other files may contain their own licence terms, or
+may fall under the standard gPXE GPL licence.
diff --git a/gpxe/src/include/gpxe/efi/Pi/PiBootMode.h b/gpxe/src/include/gpxe/efi/Pi/PiBootMode.h
new file mode 100644
index 00000000..bea69ff1
--- /dev/null
+++ b/gpxe/src/include/gpxe/efi/Pi/PiBootMode.h
@@ -0,0 +1,43 @@
+/** @file
+ Present the boot mode values in PI.
+
+ Copyright (c) 2006 - 2007, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+ @par Revision Reference:
+ Version 1.0.
+
+**/
+
+#ifndef __PI_BOOT_MODE_H__
+#define __PI_BOOT_MODE_H__
+
+#include <gpxe/efi/ProcessorBind.h>
+
+///
+/// EFI boot mode
+///
+typedef UINT32 EFI_BOOT_MODE;
+
+//
+// 0x21 - 0xf..f are reserved.
+//
+#define BOOT_WITH_FULL_CONFIGURATION 0x00
+#define BOOT_WITH_MINIMAL_CONFIGURATION 0x01
+#define BOOT_ASSUMING_NO_CONFIGURATION_CHANGES 0x02
+#define BOOT_WITH_FULL_CONFIGURATION_PLUS_DIAGNOSTICS 0x03
+#define BOOT_WITH_DEFAULT_SETTINGS 0x04
+#define BOOT_ON_S4_RESUME 0x05
+#define BOOT_ON_S5_RESUME 0x06
+#define BOOT_ON_S2_RESUME 0x10
+#define BOOT_ON_S3_RESUME 0x11
+#define BOOT_ON_FLASH_UPDATE 0x12
+#define BOOT_IN_RECOVERY_MODE 0x20
+
+#endif
diff --git a/gpxe/src/include/gpxe/efi/Pi/PiDependency.h b/gpxe/src/include/gpxe/efi/Pi/PiDependency.h
new file mode 100644
index 00000000..1f96154d
--- /dev/null
+++ b/gpxe/src/include/gpxe/efi/Pi/PiDependency.h
@@ -0,0 +1,47 @@
+/** @file
+ Present the dependency expression values in PI.
+
+ Copyright (c) 2006 - 2008, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+ @par Revision Reference:
+ Version 1.0.
+
+**/
+#ifndef __PI_DEPENDENCY_H__
+#define __PI_DEPENDENCY_H__
+
+///
+/// If present, this must be the first and only opcode,
+/// EFI_DEP_BEFORE is only used by DXE driver.
+///
+#define EFI_DEP_BEFORE 0x00
+
+///
+/// If present, this must be the first and only opcode,
+/// EFI_DEP_AFTER is only used by DXE driver.
+///
+#define EFI_DEP_AFTER 0x01
+
+#define EFI_DEP_PUSH 0x02
+#define EFI_DEP_AND 0x03
+#define EFI_DEP_OR 0x04
+#define EFI_DEP_NOT 0x05
+#define EFI_DEP_TRUE 0x06
+#define EFI_DEP_FALSE 0x07
+#define EFI_DEP_END 0x08
+
+
+///
+/// If present, this must be the first opcode,
+/// EFI_DEP_SOR is only used by DXE driver.
+///
+#define EFI_DEP_SOR 0x09
+
+#endif
diff --git a/gpxe/src/include/gpxe/efi/Pi/PiDxeCis.h b/gpxe/src/include/gpxe/efi/Pi/PiDxeCis.h
new file mode 100644
index 00000000..b57f89d8
--- /dev/null
+++ b/gpxe/src/include/gpxe/efi/Pi/PiDxeCis.h
@@ -0,0 +1,642 @@
+/** @file
+ Include file matches things in PI.
+
+ Copyright (c) 2006 - 2008, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+ @par Revision Reference:
+ Version 1.0.
+
+**/
+
+#ifndef __PI_DXECIS_H__
+#define __PI_DXECIS_H__
+
+#include <gpxe/efi/Pi/PiMultiPhase.h>
+
+///
+/// Global Coherencey Domain types - Memory type
+///
+typedef enum {
+ EfiGcdMemoryTypeNonExistent,
+ EfiGcdMemoryTypeReserved,
+ EfiGcdMemoryTypeSystemMemory,
+ EfiGcdMemoryTypeMemoryMappedIo,
+ EfiGcdMemoryTypeMaximum
+} EFI_GCD_MEMORY_TYPE;
+
+///
+/// Global Coherencey Domain types - IO type
+///
+typedef enum {
+ EfiGcdIoTypeNonExistent,
+ EfiGcdIoTypeReserved,
+ EfiGcdIoTypeIo,
+ EfiGcdIoTypeMaximum
+} EFI_GCD_IO_TYPE;
+
+///
+/// The type of allocation to perform.
+///
+typedef enum {
+ EfiGcdAllocateAnySearchBottomUp,
+ EfiGcdAllocateMaxAddressSearchBottomUp,
+ EfiGcdAllocateAddress,
+ EfiGcdAllocateAnySearchTopDown,
+ EfiGcdAllocateMaxAddressSearchTopDown,
+ EfiGcdMaxAllocateType
+} EFI_GCD_ALLOCATE_TYPE;
+
+///
+/// EFI_GCD_MEMORY_SPACE_DESCRIPTOR
+///
+typedef struct {
+ ///
+ /// The physical address of the first byte in the memory region. Type
+ /// EFI_PHYSICAL_ADDRESS is defined in the AllocatePages() function
+ /// description in the UEFI 2.0 specification
+ ///
+ EFI_PHYSICAL_ADDRESS BaseAddress;
+
+ ///
+ /// The number of bytes in the memory region.
+ ///
+ UINT64 Length;
+
+ ///
+ /// The bit mask of attributes that the memory region is capable of supporting. The bit
+ /// mask of available attributes is defined in the GetMemoryMap() function description
+ /// in the UEFI 2.0 specification.
+ ///
+ UINT64 Capabilities;
+ ///
+ /// The bit mask of attributes that the memory region is currently using. The bit mask of
+ /// available attributes is defined in GetMemoryMap().
+ ///
+ UINT64 Attributes;
+ ///
+ /// Type of the memory region. Type EFI_GCD_MEMORY_TYPE is defined in the
+ /// AddMemorySpace() function description
+ ///
+ EFI_GCD_MEMORY_TYPE GcdMemoryType;
+
+ ///
+ /// The image handle of the agent that allocated the memory resource described by
+ /// PhysicalStart and NumberOfBytes. If this field is NULL, then the memory
+ /// resource is not currently allocated. Type EFI_HANDLE is defined in
+ /// InstallProtocolInterface() in the UEFI 2.0 specification.
+ ///
+ EFI_HANDLE ImageHandle;
+
+ ///
+ /// The device handle for which the memory resource has been allocated. If
+ /// ImageHandle is NULL, then the memory resource is not currently allocated. If this
+ /// field is NULL, then the memory resource is not associated with a device that is
+ /// described by a device handle. Type EFI_HANDLE is defined in
+ /// InstallProtocolInterface() in the UEFI 2.0 specification.
+ ///
+ EFI_HANDLE DeviceHandle;
+} EFI_GCD_MEMORY_SPACE_DESCRIPTOR;
+
+///
+/// EFI_GCD_IO_SPACE_DESCRIPTOR
+///
+typedef struct {
+ ///
+ /// Physical address of the first byte in the I/O region. Type
+ /// EFI_PHYSICAL_ADDRESS is defined in the AllocatePages() function
+ /// description in the UEFI 2.0 specification.
+ ///
+ EFI_PHYSICAL_ADDRESS BaseAddress;
+
+ ///
+ /// Number of bytes in the I/O region.
+ ///
+ UINT64 Length;
+
+ ///
+ /// Type of the I/O region. Type EFI_GCD_IO_TYPE is defined in the
+ /// AddIoSpace() function description.
+ ///
+ EFI_GCD_IO_TYPE GcdIoType;
+
+ ///
+ /// The image handle of the agent that allocated the I/O resource described by
+ /// PhysicalStart and NumberOfBytes. If this field is NULL, then the I/O
+ /// resource is not currently allocated. Type EFI_HANDLE is defined in
+ /// InstallProtocolInterface() in the UEFI 2.0 specification.
+ ///
+ EFI_HANDLE ImageHandle;
+
+ ///
+ /// The device handle for which the I/O resource has been allocated. If ImageHandle
+ /// is NULL, then the I/O resource is not currently allocated. If this field is NULL, then
+ /// the I/O resource is not associated with a device that is described by a device handle.
+ /// Type EFI_HANDLE is defined in InstallProtocolInterface() in the UEFI
+ /// 2.0 specification.
+ ///
+ EFI_HANDLE DeviceHandle;
+} EFI_GCD_IO_SPACE_DESCRIPTOR;
+
+
+/**
+ Adds reserved memory, system memory, or memory-mapped I/O resources to the
+ global coherency domain of the processor.
+
+ @param GcdMemoryType The type of memory resource being added.
+ @param BaseAddress The physical address that is the start address
+ of the memory resource being added.
+ @param Length The size, in bytes, of the memory resource that
+ is being added.
+ @param Capabilities The bit mask of attributes that the memory
+ resource region supports.
+
+ @retval EFI_SUCCESS The memory resource was added to the global
+ coherency domain of the processor.
+ @retval EFI_INVALID_PARAMETER GcdMemoryType is invalid.
+ @retval EFI_INVALID_PARAMETER Length is zero.
+ @retval EFI_OUT_OF_RESOURCES There are not enough system resources to add
+ the memory resource to the global coherency
+ domain of the processor.
+ @retval EFI_UNSUPPORTED The processor does not support one or more bytes
+ of the memory resource range specified by
+ BaseAddress and Length.
+ @retval EFI_ACCESS_DENIED One or more bytes of the memory resource range
+ specified by BaseAddress and Length conflicts
+ with a memory resource range that was previously
+ added to the global coherency domain of the processor.
+ @retval EFI_ACCESS_DENIED One or more bytes of the memory resource range
+ specified by BaseAddress and Length was allocated
+ in a prior call to AllocateMemorySpace()..
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_ADD_MEMORY_SPACE)(
+ IN EFI_GCD_MEMORY_TYPE GcdMemoryType,
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN UINT64 Capabilities
+ );
+
+/**
+ Allocates nonexistent memory, reserved memory, system memory, or memorymapped
+ I/O resources from the global coherency domain of the processor.
+
+ @param GcdAllocateType The type of allocation to perform.
+ @param GcdMemoryType The type of memory resource being allocated.
+ @param Alignment The log base 2 of the boundary that BaseAddress must
+ be aligned on output. Align with 2^Alignment.
+ @param Length The size in bytes of the memory resource range that
+ is being allocated.
+ @param BaseAddress A pointer to a physical address to allocate.
+ @param Imagehandle The image handle of the agent that is allocating
+ the memory resource.
+ @param DeviceHandle The device handle for which the memory resource
+ is being allocated.
+
+ @retval EFI_INVALID_PARAMETER GcdAllocateType is invalid.
+ @retval EFI_INVALID_PARAMETER GcdMemoryType is invalid.
+ @retval EFI_INVALID_PARAMETER Length is zero.
+ @retval EFI_INVALID_PARAMETER BaseAddress is NULL.
+ @retval EFI_INVALID_PARAMETER ImageHandle is NULL.
+ @retval EFI_NOT_FOUND The memory resource request could not be satisfied.
+ No descriptor contains the desired space.
+ @retval EFI_OUT_OF_RESOURCES There are not enough system resources to allocate the memory
+ resource from the global coherency domain of the processor.
+ @retval EFI_SUCCESS The memory resource was allocated from the global coherency
+ domain of the processor.
+
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_ALLOCATE_MEMORY_SPACE)(
+ IN EFI_GCD_ALLOCATE_TYPE GcdAllocateType,
+ IN EFI_GCD_MEMORY_TYPE GcdMemoryType,
+ IN UINTN Alignment,
+ IN UINT64 Length,
+ IN OUT EFI_PHYSICAL_ADDRESS *BaseAddress,
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_HANDLE DeviceHandle OPTIONAL
+ );
+
+/**
+ Frees nonexistent memory, reserved memory, system memory, or memory-mapped
+ I/O resources from the global coherency domain of the processor.
+
+ @param BaseAddress The physical address that is the start address of the memory resource being freed.
+ @param Length The size in bytes of the memory resource range that is being freed.
+
+ @retval EFI_SUCCESS The memory resource was freed from the global coherency domain of
+ the processor.
+ @retval EFI_INVALID_PARAMETER Length is zero.
+ @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory
+ resource range specified by BaseAddress and Length.
+ @retval EFI_NOT_FOUND The memory resource range specified by BaseAddress and
+ Length was not allocated with previous calls to AllocateMemorySpace().
+ @retval EFI_OUT_OF_RESOURCES There are not enough system resources to free the memory resource
+ from the global coherency domain of the processor.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_FREE_MEMORY_SPACE)(
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length
+ );
+
+/**
+ Removes reserved memory, system memory, or memory-mapped I/O resources from
+ the global coherency domain of the processor.
+
+ @param BaseAddress The physical address that is the start address of the memory resource being removed.
+ @param Length The size in bytes of the memory resource that is being removed.
+
+ @retval EFI_SUCCESS The memory resource was removed from the global coherency
+ domain of the processor.
+ @retval EFI_INVALID_PARAMETER Length is zero.
+ @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory
+ resource range specified by BaseAddress and Length.
+ @retval EFI_NOT_FOUND One or more bytes of the memory resource range specified by
+ BaseAddress and Length was not added with previous calls to
+ AddMemorySpace().
+ @retval EFI_ACCESS_DEFINED One or more bytes of the memory resource range specified by
+ BaseAddress and Length has been allocated with AllocateMemorySpace().
+ @retval EFI_OUT_OF_RESOURCES There are not enough system resources to remove the memory
+ resource from the global coherency domain of the processor.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_REMOVE_MEMORY_SPACE)(
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length
+ );
+
+/**
+ Retrieves the descriptor for a memory region containing a specified address.
+
+ @param BaseAddress The physical address that is the start address of a memory region.
+ @param Descriptor A pointer to a caller allocated descriptor.
+
+ @retval EFI_SUCCESS The descriptor for the memory resource region containing
+ BaseAddress was returned in Descriptor.
+ @retval EFI_INVALID_PARAMETER Descriptor is NULL.
+ @retval EFI_NOT_FOUND A memory resource range containing BaseAddress was not found.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_GET_MEMORY_SPACE_DESCRIPTOR)(
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ OUT EFI_GCD_MEMORY_SPACE_DESCRIPTOR *Descriptor
+ );
+
+/**
+ Modifies the attributes for a memory region in the global coherency domain of the
+ processor.
+
+ @param BaseAddress The physical address that is the start address of a memory region.
+ @param Length The size in bytes of the memory region.
+ @param Attributes The bit mask of attributes to set for the memory region.
+
+ @retval EFI_SUCCESS The attributes were set for the memory region.
+ @retval EFI_INVALID_PARAMETER Length is zero.
+ @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory
+ resource range specified by BaseAddress and Length.
+ @retval EFI_UNSUPPORTED The bit mask of attributes is not support for the memory resource
+ range specified by BaseAddress and Length.
+ @retval EFI_ACCESS_DEFINED The attributes for the memory resource range specified by
+ BaseAddress and Length cannot be modified.
+ @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
+ the memory resource range.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SET_MEMORY_SPACE_ATTRIBUTES)(
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN UINT64 Attributes
+ );
+
+/**
+ Returns a map of the memory resources in the global coherency domain of the
+ processor.
+
+ @param NumberOfDescriptors A pointer to number of descriptors returned in the MemorySpaceMap buffer.
+ @param MemorySpaceMap A pointer to the array of EFI_GCD_MEMORY_SPACE_DESCRIPTORs.
+
+ @retval EFI_SUCCESS The memory space map was returned in the MemorySpaceMap
+ buffer, and the number of descriptors in MemorySpaceMap was
+ returned in NumberOfDescriptors.
+ @retval EFI_INVALID_PARAMETER NumberOfDescriptors is NULL.
+ @retval EFI_INVALID_PARAMETER MemorySpaceMap is NULL.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources to allocate MemorySpaceMap.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_GET_MEMORY_SPACE_MAP)(
+ OUT UINTN *NumberOfDescriptors,
+ OUT EFI_GCD_MEMORY_SPACE_DESCRIPTOR **MemorySpaceMap
+ );
+
+/**
+ Adds reserved I/O or I/O resources to the global coherency domain of the processor.
+
+ @param GcdIoType The type of I/O resource being added.
+ @param BaseAddress The physical address that is the start address of the I/O resource being added.
+ @param Length The size in bytes of the I/O resource that is being added.
+
+ @retval EFI_SUCCESS The I/O resource was added to the global coherency domain of
+ the processor.
+ @retval EFI_INVALID_PARAMETER GcdIoType is invalid.
+ @retval EFI_INVALID_PARAMETER Length is zero.
+ @retval EFI_OUT_OF_RESOURCES There are not enough system resources to add the I/O resource to
+ the global coherency domain of the processor.
+ @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the I/O
+ resource range specified by BaseAddress and Length.
+ @retval EFI_ACCESS_DENIED One or more bytes of the I/O resource range specified by
+ BaseAddress and Length conflicts with an I/O resource
+ range that was previously added to the global coherency domain
+ of the processor.
+ @retval EFI_ACCESS_DENIED One or more bytes of the I/O resource range specified by
+ BaseAddress and Length was allocated in a prior call to
+ AllocateIoSpace().
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_ADD_IO_SPACE)(
+ IN EFI_GCD_IO_TYPE GcdIoType,
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length
+ );
+
+/**
+ Allocates nonexistent I/O, reserved I/O, or I/O resources from the global coherency
+ domain of the processor.
+
+ @param GcdAllocateType The type of allocation to perform.
+ @param GcdIoType The type of I/O resource being allocated.
+ @param Alignment The log base 2 of the boundary that BaseAddress must be aligned on output.
+ @param Length The size in bytes of the I/O resource range that is being allocated.
+ @param BaseAddress A pointer to a physical address.
+ @param Imagehandle The image handle of the agent that is allocating the I/O resource.
+ @param DeviceHandle The device handle for which the I/O resource is being allocated.
+
+ @retval EFI_SUCCESS The I/O resource was allocated from the global coherency domain
+ of the processor.
+ @retval EFI_INVALID_PARAMETER GcdAllocateType is invalid.
+ @retval EFI_INVALID_PARAMETER GcdIoType is invalid.
+ @retval EFI_INVALID_PARAMETER Length is zero.
+ @retval EFI_INVALID_PARAMETER BaseAddress is NULL.
+ @retval EFI_INVALID_PARAMETER ImageHandle is NULL.
+ @retval EFI_OUT_OF_RESOURCES There are not enough system resources to allocate the I/O
+ resource from the global coherency domain of the processor.
+ @retval EFI_NOT_FOUND The I/O resource request could not be satisfied.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_ALLOCATE_IO_SPACE)(
+ IN EFI_GCD_ALLOCATE_TYPE GcdAllocateType,
+ IN EFI_GCD_IO_TYPE GcdIoType,
+ IN UINTN Alignment,
+ IN UINT64 Length,
+ IN OUT EFI_PHYSICAL_ADDRESS *BaseAddress,
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_HANDLE DeviceHandle OPTIONAL
+ );
+
+/**
+ Frees nonexistent I/O, reserved I/O, or I/O resources from the global coherency
+ domain of the processor.
+
+ @param BaseAddress The physical address that is the start address of the I/O resource being freed.
+ @param Length The size in bytes of the I/O resource range that is being freed.
+
+ @retval EFI_SUCCESS The I/O resource was freed from the global coherency domain of the
+ processor.
+ @retval EFI_INVALID_PARAMETER Length is zero.
+ @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the I/O resource
+ range specified by BaseAddress and Length.
+ @retval EFI_NOT_FOUND The I/O resource range specified by BaseAddress and Length
+ was not allocated with previous calls to AllocateIoSpace().
+ @retval EFI_OUT_OF_RESOURCES There are not enough system resources to free the I/O resource from
+ the global coherency domain of the processor.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_FREE_IO_SPACE)(
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length
+ );
+
+/**
+ Removes reserved I/O or I/O resources from the global coherency domain of the
+ processor.
+
+ @param BaseAddress A pointer to a physical address that is the start address of the I/O resource being
+ removed.
+ @param Length The size in bytes of the I/O resource that is being removed.
+
+ @retval EFI_SUCCESS The I/O resource was removed from the global coherency domain
+ of the processor.
+ @retval EFI_INVALID_PARAMETER Length is zero.
+ @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the I/O
+ resource range specified by BaseAddress and Length.
+ @retval EFI_NOT_FOUND One or more bytes of the I/O resource range specified by
+ BaseAddress and Length was not added with previous
+ calls to AddIoSpace().
+ @retval EFI_ACCESS_DENIED One or more bytes of the I/O resource range specified by
+ BaseAddress and Length has been allocated with
+ AllocateIoSpace().
+ @retval EFI_OUT_OF_RESOURCES There are not enough system resources to remove the I/O
+ resource from the global coherency domain of the processor.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_REMOVE_IO_SPACE)(
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length
+ );
+
+/**
+ Retrieves the descriptor for an I/O region containing a specified address.
+
+ @param BaseAddress The physical address that is the start address of an I/O region.
+ @param Descriptor A pointer to a caller allocated descriptor.
+
+ @retval EFI_SUCCESS The descriptor for the I/O resource region containing
+ BaseAddress was returned in Descriptor.
+ @retval EFI_INVALID_PARAMETER Descriptor is NULL.
+ @retval EFI_NOT_FOUND An I/O resource range containing BaseAddress was not found.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_GET_IO_SPACE_DESCRIPTOR)(
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ OUT EFI_GCD_IO_SPACE_DESCRIPTOR *Descriptor
+ );
+
+/**
+ Returns a map of the I/O resources in the global coherency domain of the processor.
+
+ @param NumberOfDescriptors A pointer to number of descriptors returned in the IoSpaceMap buffer.
+ @param MemorySpaceMap A pointer to the array of EFI_GCD_IO_SPACE_DESCRIPTORs.
+
+ @retval EFI_SUCCESS The I/O space map was returned in the IoSpaceMap buffer, and
+ the number of descriptors in IoSpaceMap was returned in
+ NumberOfDescriptors.
+ @retval EFI_INVALID_PARAMETER NumberOfDescriptors is NULL.
+ @retval EFI_INVALID_PARAMETER IoSpaceMap is NULL.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources to allocate IoSpaceMap.
+
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_GET_IO_SPACE_MAP)(
+ OUT UINTN *NumberOfDescriptors,
+ OUT EFI_GCD_IO_SPACE_DESCRIPTOR **IoSpaceMap
+ );
+
+
+
+/**
+ Loads and executed DXE drivers from firmware volumes.
+
+ The Dispatch() function searches for DXE drivers in firmware volumes that have been
+ installed since the last time the Dispatch() service was called. It then evaluates
+ the dependency expressions of all the DXE drivers and loads and executes those DXE
+ drivers whose dependency expression evaluate to TRUE. This service must interact with
+ the Security Architectural Protocol to authenticate DXE drivers before they are executed.
+ This process is continued until no more DXE drivers can be executed.
+
+ @retval EFI_SUCCESS One or more DXE driver were dispatched.
+ @retval EFI_NOT_FOUND No DXE drivers were dispatched.
+ @retval EFI_ALREADY_STARTED An attempt is being made to start the DXE Dispatcher recursively.
+ Thus no action was taken.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_DISPATCH)(
+ VOID
+ );
+
+/**
+ Clears the Schedule on Request (SOR) flag for a component that is stored in a firmware volume.
+
+ @param FirmwareVolumeHandle The handle of the firmware volume that contains the file specified by FileName.
+ @param FileName A pointer to the name of the file in a firmware volume.
+
+ @retval EFI_SUCCESS The DXE driver was found and its SOR bit was cleared.
+ @retval EFI_NOT_FOUND The DXE driver does not exist, or the DXE driver exists and its SOR
+ bit is not set.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SCHEDULE)(
+ IN EFI_HANDLE FirmwareVolumeHandle,
+ IN CONST EFI_GUID *FileName
+ );
+
+/**
+ Promotes a file stored in a firmware volume from the untrusted to the trusted state.
+
+ @param FirmwareVolumeHandle The handle of the firmware volume that contains the file specified by FileName.
+ @param DriverName A pointer to the name of the file in a firmware volume.
+
+ @return Status of promoting FFS from untrusted to trusted
+ state.
+ @retval EFI_NOT_FOUND The file was not found in the untrusted state.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_TRUST)(
+ IN EFI_HANDLE FirmwareVolumeHandle,
+ IN CONST EFI_GUID *FileName
+ );
+
+/**
+ Creates a firmware volume handle for a firmware volume that is present in system memory.
+
+ @param FirmwareVolumeHeader A pointer to the header of the firmware volume.
+ @param Size The size, in bytes, of the firmware volume.
+ @param FirmwareVolumeHandle On output, a pointer to the created handle.
+
+ @retval EFI_SUCCESS The EFI_FIRMWARE_VOLUME_PROTOCOL and
+ EFI_DEVICE_PATH_PROTOCOL were installed onto
+ FirmwareVolumeHandle for the firmware volume described
+ by FirmwareVolumeHeader and Size.
+ @retval EFI_VOLUME_CORRUPTED The firmware volume described by FirmwareVolumeHeader
+ and Size is corrupted.
+ @retval EFI_OUT_OF_RESOURCES There are not enough system resources available to produce the
+ EFI_FIRMWARE_VOLUME_PROTOCOL and EFI_DEVICE_PATH_PROTOCOL
+ for the firmware volume described by FirmwareVolumeHeader and Size.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PROCESS_FIRMWARE_VOLUME)(
+ IN CONST VOID *FirmwareVolumeHeader,
+ IN UINTN Size,
+ OUT EFI_HANDLE *FirmwareVolumeHandle
+ );
+
+//
+// DXE Services Table
+//
+#define DXE_SERVICES_SIGNATURE 0x565245535f455844ULL
+#define DXE_SERVICES_REVISION ((1<<16) | (00))
+
+typedef struct {
+ EFI_TABLE_HEADER Hdr;
+
+ //
+ // Global Coherency Domain Services
+ //
+ EFI_ADD_MEMORY_SPACE AddMemorySpace;
+ EFI_ALLOCATE_MEMORY_SPACE AllocateMemorySpace;
+ EFI_FREE_MEMORY_SPACE FreeMemorySpace;
+ EFI_REMOVE_MEMORY_SPACE RemoveMemorySpace;
+ EFI_GET_MEMORY_SPACE_DESCRIPTOR GetMemorySpaceDescriptor;
+ EFI_SET_MEMORY_SPACE_ATTRIBUTES SetMemorySpaceAttributes;
+ EFI_GET_MEMORY_SPACE_MAP GetMemorySpaceMap;
+ EFI_ADD_IO_SPACE AddIoSpace;
+ EFI_ALLOCATE_IO_SPACE AllocateIoSpace;
+ EFI_FREE_IO_SPACE FreeIoSpace;
+ EFI_REMOVE_IO_SPACE RemoveIoSpace;
+ EFI_GET_IO_SPACE_DESCRIPTOR GetIoSpaceDescriptor;
+ EFI_GET_IO_SPACE_MAP GetIoSpaceMap;
+
+ //
+ // Dispatcher Services
+ //
+ EFI_DISPATCH Dispatch;
+ EFI_SCHEDULE Schedule;
+ EFI_TRUST Trust;
+ //
+ // Service to process a single firmware volume found in a capsule
+ //
+ EFI_PROCESS_FIRMWARE_VOLUME ProcessFirmwareVolume;
+} DXE_SERVICES;
+
+typedef DXE_SERVICES EFI_DXE_SERVICES;
+
+#endif
diff --git a/gpxe/src/include/gpxe/efi/Pi/PiFirmwareFile.h b/gpxe/src/include/gpxe/efi/Pi/PiFirmwareFile.h
new file mode 100644
index 00000000..a25e98c5
--- /dev/null
+++ b/gpxe/src/include/gpxe/efi/Pi/PiFirmwareFile.h
@@ -0,0 +1,242 @@
+/** @file
+ The firmware file related definitions in PI.
+
+ Copyright (c) 2006 - 2008, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+ @par Revision Reference:
+ Version 1.0.
+
+**/
+
+
+#ifndef __PI_FIRMWARE_FILE_H__
+#define __PI_FIRMWARE_FILE_H__
+
+#include <gpxe/efi/ProcessorBind.h>
+
+#pragma pack(1)
+///
+/// Used to verify the integrity of the file.
+///
+typedef union {
+ struct {
+ UINT8 Header;
+ UINT8 File;
+ } Checksum;
+ UINT16 Checksum16;
+} EFI_FFS_INTEGRITY_CHECK;
+
+typedef UINT8 EFI_FV_FILETYPE;
+typedef UINT8 EFI_FFS_FILE_ATTRIBUTES;
+typedef UINT8 EFI_FFS_FILE_STATE;
+
+///
+/// File Types Definitions
+///
+#define EFI_FV_FILETYPE_ALL 0x00
+#define EFI_FV_FILETYPE_RAW 0x01
+#define EFI_FV_FILETYPE_FREEFORM 0x02
+#define EFI_FV_FILETYPE_SECURITY_CORE 0x03
+#define EFI_FV_FILETYPE_PEI_CORE 0x04
+#define EFI_FV_FILETYPE_DXE_CORE 0x05
+#define EFI_FV_FILETYPE_PEIM 0x06
+#define EFI_FV_FILETYPE_DRIVER 0x07
+#define EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER 0x08
+#define EFI_FV_FILETYPE_APPLICATION 0x09
+#define EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE 0x0B
+#define EFI_FV_FILETYPE_OEM_MIN 0xc0
+#define EFI_FV_FILETYPE_OEM_MAX 0xdf
+#define EFI_FV_FILETYPE_DEBUG_MIN 0xe0
+#define EFI_FV_FILETYPE_DEBUG_MAX 0xef
+#define EFI_FV_FILETYPE_FFS_MIN 0xf0
+#define EFI_FV_FILETYPE_FFS_MAX 0xff
+#define EFI_FV_FILETYPE_FFS_PAD 0xf0
+///
+/// FFS File Attributes.
+///
+#define FFS_ATTRIB_FIXED 0x04
+#define FFS_ATTRIB_DATA_ALIGNMENT 0x38
+#define FFS_ATTRIB_CHECKSUM 0x40
+
+///
+/// FFS File State Bits.
+///
+#define EFI_FILE_HEADER_CONSTRUCTION 0x01
+#define EFI_FILE_HEADER_VALID 0x02
+#define EFI_FILE_DATA_VALID 0x04
+#define EFI_FILE_MARKED_FOR_UPDATE 0x08
+#define EFI_FILE_DELETED 0x10
+#define EFI_FILE_HEADER_INVALID 0x20
+
+
+///
+/// Each file begins with the header that describe the
+/// contents and state of the files.
+///
+typedef struct {
+ EFI_GUID Name;
+ EFI_FFS_INTEGRITY_CHECK IntegrityCheck;
+ EFI_FV_FILETYPE Type;
+ EFI_FFS_FILE_ATTRIBUTES Attributes;
+ UINT8 Size[3];
+ EFI_FFS_FILE_STATE State;
+} EFI_FFS_FILE_HEADER;
+
+
+typedef UINT8 EFI_SECTION_TYPE;
+
+///
+/// Pseudo type. It is
+/// used as a wild card when retrieving sections. The section
+/// type EFI_SECTION_ALL matches all section types.
+///
+#define EFI_SECTION_ALL 0x00
+
+///
+/// Encapsulation section Type values
+///
+#define EFI_SECTION_COMPRESSION 0x01
+
+#define EFI_SECTION_GUID_DEFINED 0x02
+
+///
+/// Leaf section Type values
+///
+#define EFI_SECTION_PE32 0x10
+#define EFI_SECTION_PIC 0x11
+#define EFI_SECTION_TE 0x12
+#define EFI_SECTION_DXE_DEPEX 0x13
+#define EFI_SECTION_VERSION 0x14
+#define EFI_SECTION_USER_INTERFACE 0x15
+#define EFI_SECTION_COMPATIBILITY16 0x16
+#define EFI_SECTION_FIRMWARE_VOLUME_IMAGE 0x17
+#define EFI_SECTION_FREEFORM_SUBTYPE_GUID 0x18
+#define EFI_SECTION_RAW 0x19
+#define EFI_SECTION_PEI_DEPEX 0x1B
+
+///
+/// Common section header
+///
+typedef struct {
+ UINT8 Size[3];
+ EFI_SECTION_TYPE Type;
+} EFI_COMMON_SECTION_HEADER;
+
+///
+/// Leaf section type that contains an
+/// IA-32 16-bit executable image.
+///
+typedef EFI_COMMON_SECTION_HEADER EFI_COMPATIBILITY16_SECTION;
+
+///
+/// CompressionType of EFI_COMPRESSION_SECTION.
+///
+#define EFI_NOT_COMPRESSED 0x00
+#define EFI_STANDARD_COMPRESSION 0x01
+///
+/// An encapsulation section type in which the
+/// section data is compressed.
+///
+typedef struct {
+ EFI_COMMON_SECTION_HEADER CommonHeader;
+ UINT32 UncompressedLength;
+ UINT8 CompressionType;
+} EFI_COMPRESSION_SECTION;
+
+///
+/// Leaf section which could be used to determine the dispatch order of DXEs.
+///
+typedef EFI_COMMON_SECTION_HEADER EFI_DXE_DEPEX_SECTION;
+
+///
+/// Leaf section witch contains a PI FV.
+///
+typedef EFI_COMMON_SECTION_HEADER EFI_FIRMWARE_VOLUME_IMAGE_SECTION;
+
+///
+/// Leaf section which contains a single GUID.
+///
+typedef struct {
+ EFI_COMMON_SECTION_HEADER CommonHeader;
+ EFI_GUID SubTypeGuid;
+} EFI_FREEFORM_SUBTYPE_GUID_SECTION;
+
+///
+/// Attributes of EFI_GUID_DEFINED_SECTION
+///
+#define EFI_GUIDED_SECTION_PROCESSING_REQUIRED 0x01
+#define EFI_GUIDED_SECTION_AUTH_STATUS_VALID 0x02
+///
+/// Leaf section which is encapsulation defined by specific GUID
+///
+typedef struct {
+ EFI_COMMON_SECTION_HEADER CommonHeader;
+ EFI_GUID SectionDefinitionGuid;
+ UINT16 DataOffset;
+ UINT16 Attributes;
+} EFI_GUID_DEFINED_SECTION;
+
+///
+/// Leaf section which contains PE32+ image.
+///
+typedef EFI_COMMON_SECTION_HEADER EFI_PE32_SECTION;
+
+
+///
+/// Leaf section which used to determine the dispatch order of PEIMs.
+///
+typedef EFI_COMMON_SECTION_HEADER EFI_PEI_DEPEX_SECTION;
+
+///
+/// Leaf section which constains the position-independent-code image.
+///
+typedef EFI_COMMON_SECTION_HEADER EFI_TE_SECTION;
+
+///
+/// Leaf section which contains an array of zero or more bytes.
+///
+typedef EFI_COMMON_SECTION_HEADER EFI_RAW_SECTION;
+
+///
+/// Leaf section which contains a unicode string that
+/// is human readable file name.
+///
+typedef struct {
+ EFI_COMMON_SECTION_HEADER CommonHeader;
+
+ ///
+ /// Array of unicode string.
+ ///
+ CHAR16 FileNameString[1];
+} EFI_USER_INTERFACE_SECTION;
+
+
+///
+/// Leaf section which contains a numeric build number and
+/// an optional unicode string that represent the file revision.
+///
+typedef struct {
+ EFI_COMMON_SECTION_HEADER CommonHeader;
+ UINT16 BuildNumber;
+
+ ///
+ /// Array of unicode string.
+ ///
+ CHAR16 VersionString[1];
+} EFI_VERSION_SECTION;
+
+
+#define SECTION_SIZE(SectionHeaderPtr) \
+ ((UINT32) (*((UINT32 *) ((EFI_COMMON_SECTION_HEADER *) SectionHeaderPtr)->Size) & 0x00ffffff))
+
+#pragma pack()
+
+#endif
+
diff --git a/gpxe/src/include/gpxe/efi/Pi/PiFirmwareVolume.h b/gpxe/src/include/gpxe/efi/Pi/PiFirmwareVolume.h
new file mode 100644
index 00000000..39c81b19
--- /dev/null
+++ b/gpxe/src/include/gpxe/efi/Pi/PiFirmwareVolume.h
@@ -0,0 +1,154 @@
+/** @file
+ The firmware volume related definitions in PI.
+
+ Copyright (c) 2006 - 2007, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+ @par Revision Reference:
+ Version 1.0.
+
+**/
+
+#ifndef __PI_FIRMWAREVOLUME_H__
+#define __PI_FIRMWAREVOLUME_H__
+
+#include <gpxe/efi/ProcessorBind.h>
+
+///
+/// EFI_FV_FILE_ATTRIBUTES
+///
+typedef UINT32 EFI_FV_FILE_ATTRIBUTES;
+
+//
+// Value of EFI_FV_FILE_ATTRIBUTES.
+//
+#define EFI_FV_FILE_ATTRIB_ALIGNMENT 0x0000001F
+#define EFI_FV_FILE_ATTRIB_FIXED 0x00000100
+#define EFI_FV_FILE_ATTRIB_MEMORY_MAPPED 0x00000200
+
+///
+/// type of EFI FVB attribute
+///
+typedef UINT32 EFI_FVB_ATTRIBUTES_2;
+
+//
+// Attributes bit definitions
+//
+#define EFI_FVB2_READ_DISABLED_CAP 0x00000001
+#define EFI_FVB2_READ_ENABLED_CAP 0x00000002
+#define EFI_FVB2_READ_STATUS 0x00000004
+#define EFI_FVB2_WRITE_DISABLED_CAP 0x00000008
+#define EFI_FVB2_WRITE_ENABLED_CAP 0x00000010
+#define EFI_FVB2_WRITE_STATUS 0x00000020
+#define EFI_FVB2_LOCK_CAP 0x00000040
+#define EFI_FVB2_LOCK_STATUS 0x00000080
+#define EFI_FVB2_STICKY_WRITE 0x00000200
+#define EFI_FVB2_MEMORY_MAPPED 0x00000400
+#define EFI_FVB2_ERASE_POLARITY 0x00000800
+#define EFI_FVB2_READ_LOCK_CAP 0x00001000
+#define EFI_FVB2_READ_LOCK_STATUS 0x00002000
+#define EFI_FVB2_WRITE_LOCK_CAP 0x00004000
+#define EFI_FVB2_WRITE_LOCK_STATUS 0x00008000
+#define EFI_FVB2_ALIGNMENT 0x001F0000
+#define EFI_FVB2_ALIGNMENT_1 0x00000000
+#define EFI_FVB2_ALIGNMENT_2 0x00010000
+#define EFI_FVB2_ALIGNMENT_4 0x00020000
+#define EFI_FVB2_ALIGNMENT_8 0x00030000
+#define EFI_FVB2_ALIGNMENT_16 0x00040000
+#define EFI_FVB2_ALIGNMENT_32 0x00050000
+#define EFI_FVB2_ALIGNMENT_64 0x00060000
+#define EFI_FVB2_ALIGNMENT_128 0x00070000
+#define EFI_FVB2_ALIGNMENT_256 0x00080000
+#define EFI_FVB2_ALIGNMENT_512 0x00090000
+#define EFI_FVB2_ALIGNMENT_1K 0x000A0000
+#define EFI_FVB2_ALIGNMENT_2K 0x000B0000
+#define EFI_FVB2_ALIGNMENT_4K 0x000C0000
+#define EFI_FVB2_ALIGNMENT_8K 0x000D0000
+#define EFI_FVB2_ALIGNMENT_16K 0x000E0000
+#define EFI_FVB2_ALIGNMENT_32K 0x000F0000
+#define EFI_FVB2_ALIGNMENT_64K 0x00100000
+#define EFI_FVB2_ALIGNMENT_128K 0x00110000
+#define EFI_FVB2_ALIGNMENT_256K 0x00120000
+#define EFI_FVB2_ALIGNMNET_512K 0x00130000
+#define EFI_FVB2_ALIGNMENT_1M 0x00140000
+#define EFI_FVB2_ALIGNMENT_2M 0x00150000
+#define EFI_FVB2_ALIGNMENT_4M 0x00160000
+#define EFI_FVB2_ALIGNMENT_8M 0x00170000
+#define EFI_FVB2_ALIGNMENT_16M 0x00180000
+#define EFI_FVB2_ALIGNMENT_32M 0x00190000
+#define EFI_FVB2_ALIGNMENT_64M 0x001A0000
+#define EFI_FVB2_ALIGNMENT_128M 0x001B0000
+#define EFI_FVB2_ALIGNMENT_256M 0x001C0000
+#define EFI_FVB2_ALIGNMENT_512M 0x001D0000
+#define EFI_FVB2_ALIGNMENT_1G 0x001E0000
+#define EFI_FVB2_ALIGNMENT_2G 0x001F0000
+
+
+typedef struct {
+ UINT32 NumBlocks;
+ UINT32 Length;
+} EFI_FV_BLOCK_MAP_ENTRY;
+
+///
+/// Describes the features and layout of the firmware volume.
+///
+typedef struct {
+ UINT8 ZeroVector[16];
+ EFI_GUID FileSystemGuid;
+ UINT64 FvLength;
+ UINT32 Signature;
+ EFI_FVB_ATTRIBUTES_2 Attributes;
+ UINT16 HeaderLength;
+ UINT16 Checksum;
+ UINT16 ExtHeaderOffset;
+ UINT8 Reserved[1];
+ UINT8 Revision;
+ EFI_FV_BLOCK_MAP_ENTRY BlockMap[1];
+} EFI_FIRMWARE_VOLUME_HEADER;
+
+#define EFI_FVH_SIGNATURE EFI_SIGNATURE_32 ('_', 'F', 'V', 'H')
+
+///
+/// Firmware Volume Header Revision definition
+///
+#define EFI_FVH_REVISION 0x02
+
+///
+/// Extension header pointed by ExtHeaderOffset of volume header.
+///
+typedef struct {
+ EFI_GUID FvName;
+ UINT32 ExtHeaderSize;
+} EFI_FIRMWARE_VOLUME_EXT_HEADER;
+
+///
+/// Entry struture for describing FV extension header
+///
+typedef struct {
+ UINT16 ExtEntrySize;
+ UINT16 ExtEntryType;
+} EFI_FIRMWARE_VOLUME_EXT_ENTRY;
+
+#define EFI_FV_EXT_TYPE_OEM_TYPE 0x01
+///
+/// This extension header provides a mapping between a GUID and an OEM file type.
+///
+typedef struct {
+ EFI_FIRMWARE_VOLUME_EXT_ENTRY Hdr;
+ UINT32 TypeMask;
+
+ //
+ // Array of GUIDs.
+ // Each GUID represents an OEM file type.
+ //
+ EFI_GUID Types[1];
+} EFI_FIRMWARE_VOLUME_EXT_ENTRY_OEM_TYPE;
+
+
+#endif
diff --git a/gpxe/src/include/gpxe/efi/Pi/PiHob.h b/gpxe/src/include/gpxe/efi/Pi/PiHob.h
new file mode 100644
index 00000000..1a695d7e
--- /dev/null
+++ b/gpxe/src/include/gpxe/efi/Pi/PiHob.h
@@ -0,0 +1,293 @@
+/** @file
+ HOB related definitions in PI.
+
+ Copyright (c) 2006 - 2008, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+ @par Revision Reference:
+ Version 1.0.
+
+**/
+
+#ifndef __PI_HOB_H__
+#define __PI_HOB_H__
+
+#include <gpxe/efi/ProcessorBind.h>
+#include <gpxe/efi/Pi/PiBootMode.h>
+#include <gpxe/efi/Uefi/UefiBaseType.h>
+#include <gpxe/efi/Uefi/UefiMultiPhase.h>
+
+//
+// HobType of EFI_HOB_GENERIC_HEADER.
+//
+#define EFI_HOB_TYPE_HANDOFF 0x0001
+#define EFI_HOB_TYPE_MEMORY_ALLOCATION 0x0002
+#define EFI_HOB_TYPE_RESOURCE_DESCRIPTOR 0x0003
+#define EFI_HOB_TYPE_GUID_EXTENSION 0x0004
+#define EFI_HOB_TYPE_FV 0x0005
+#define EFI_HOB_TYPE_CPU 0x0006
+#define EFI_HOB_TYPE_MEMORY_POOL 0x0007
+#define EFI_HOB_TYPE_FV2 0x0009
+#define EFI_HOB_TYPE_LOAD_PEIM 0x000A
+#define EFI_HOB_TYPE_UNUSED 0xFFFE
+#define EFI_HOB_TYPE_END_OF_HOB_LIST 0xFFFF
+
+///
+/// Describes the format and size of the data inside the HOB.
+/// All HOBs must contain this generic HOB header.
+///
+typedef struct {
+ UINT16 HobType;
+ UINT16 HobLength;
+ UINT32 Reserved;
+} EFI_HOB_GENERIC_HEADER;
+
+
+///
+/// Value of version ofinEFI_HOB_HANDOFF_INFO_TABLE.
+///
+#define EFI_HOB_HANDOFF_TABLE_VERSION 0x0009
+
+///
+/// Contains general state information used by the HOB producer phase.
+/// This HOB must be the first one in the HOB list.
+///
+typedef struct {
+ EFI_HOB_GENERIC_HEADER Header;
+ UINT32 Version;
+ EFI_BOOT_MODE BootMode;
+ EFI_PHYSICAL_ADDRESS EfiMemoryTop;
+ EFI_PHYSICAL_ADDRESS EfiMemoryBottom;
+ EFI_PHYSICAL_ADDRESS EfiFreeMemoryTop;
+ EFI_PHYSICAL_ADDRESS EfiFreeMemoryBottom;
+ EFI_PHYSICAL_ADDRESS EfiEndOfHobList;
+} EFI_HOB_HANDOFF_INFO_TABLE;
+
+///
+/// EFI_HOB_MEMORY_ALLOCATION_HEADER describes the
+/// various attributes of the logical memory allocation. The type field will be used for
+/// subsequent inclusion in the UEFI memory map.
+///
+typedef struct {
+ ///
+ /// A GUID that defines the memory allocation region¡¯s type and purpose, as well as
+ /// other fields within the memory allocation HOB. This GUID is used to define the
+ /// additional data within the HOB that may be present for the memory allocation HOB.
+ /// Type EFI_GUID is defined in InstallProtocolInterface() in the UEFI 2.0
+ /// specification.
+ ///
+ EFI_GUID Name;
+
+ /// The base address of memory allocated by this HOB. Type
+ /// EFI_PHYSICAL_ADDRESS is defined in AllocatePages() in the UEFI 2.0
+ /// specification.
+ EFI_PHYSICAL_ADDRESS MemoryBaseAddress;
+
+ ///
+ /// The length in bytes of memory allocated by this HOB.
+ ///
+ UINT64 MemoryLength;
+
+ ///
+ /// Defines the type of memory allocated by this HOB. The memory type definition
+ /// follows the EFI_MEMORY_TYPE definition. Type EFI_MEMORY_TYPE is defined
+ /// in AllocatePages() in the UEFI 2.0 specification.
+ ///
+ EFI_MEMORY_TYPE MemoryType;
+
+ ///
+ /// Padding for Itanium processor family
+ ///
+ UINT8 Reserved[4];
+} EFI_HOB_MEMORY_ALLOCATION_HEADER;
+
+///
+/// Describes all memory ranges used during the HOB producer
+/// phase that exist outside the HOB list. This HOB type
+/// describes how memory is used,
+/// not the physical attributes of memory.
+///
+typedef struct {
+ EFI_HOB_GENERIC_HEADER Header;
+ EFI_HOB_MEMORY_ALLOCATION_HEADER AllocDescriptor;
+ //
+ // Additional data pertaining to the "Name" Guid memory
+ // may go here.
+ //
+} EFI_HOB_MEMORY_ALLOCATION;
+
+
+///
+/// Describes the memory stack that is produced by the HOB producer
+/// phase and upon which all postmemory-installed executable
+/// content in the HOB producer phase is executing.
+///
+typedef struct {
+ EFI_HOB_GENERIC_HEADER Header;
+ EFI_HOB_MEMORY_ALLOCATION_HEADER AllocDescriptor;
+} EFI_HOB_MEMORY_ALLOCATION_STACK;
+
+///
+/// Defines the location of the boot-strap
+/// processor (BSP) BSPStore ("Backing Store Pointer Store").
+/// This HOB is valid for the Itanium processor family only
+/// register overflow store.
+///
+typedef struct {
+ EFI_HOB_GENERIC_HEADER Header;
+ EFI_HOB_MEMORY_ALLOCATION_HEADER AllocDescriptor;
+} EFI_HOB_MEMORY_ALLOCATION_BSP_STORE;
+
+///
+/// Defines the location and entry point of the HOB consumer phase.
+///
+typedef struct {
+ EFI_HOB_GENERIC_HEADER Header;
+ EFI_HOB_MEMORY_ALLOCATION_HEADER MemoryAllocationHeader;
+ EFI_GUID ModuleName;
+ EFI_PHYSICAL_ADDRESS EntryPoint;
+} EFI_HOB_MEMORY_ALLOCATION_MODULE;
+
+///
+/// type of Recount type
+///
+typedef UINT32 EFI_RESOURCE_TYPE;
+
+//
+// Value of ResourceType in EFI_HOB_RESOURCE_DESCRIPTOR.
+//
+#define EFI_RESOURCE_SYSTEM_MEMORY 0x00000000
+#define EFI_RESOURCE_MEMORY_MAPPED_IO 0x00000001
+#define EFI_RESOURCE_IO 0x00000002
+#define EFI_RESOURCE_FIRMWARE_DEVICE 0x00000003
+#define EFI_RESOURCE_MEMORY_MAPPED_IO_PORT 0x00000004
+#define EFI_RESOURCE_MEMORY_RESERVED 0x00000005
+#define EFI_RESOURCE_IO_RESERVED 0x00000006
+#define EFI_RESOURCE_MAX_MEMORY_TYPE 0x00000007
+
+///
+/// type of recount attribute type
+///
+typedef UINT32 EFI_RESOURCE_ATTRIBUTE_TYPE;
+
+//
+// These types can be ORed together as needed.
+//
+// The first three enumerations describe settings
+//
+#define EFI_RESOURCE_ATTRIBUTE_PRESENT 0x00000001
+#define EFI_RESOURCE_ATTRIBUTE_INITIALIZED 0x00000002
+#define EFI_RESOURCE_ATTRIBUTE_TESTED 0x00000004
+//
+// The rest of the settings describe capabilities
+//
+#define EFI_RESOURCE_ATTRIBUTE_SINGLE_BIT_ECC 0x00000008
+#define EFI_RESOURCE_ATTRIBUTE_MULTIPLE_BIT_ECC 0x00000010
+#define EFI_RESOURCE_ATTRIBUTE_ECC_RESERVED_1 0x00000020
+#define EFI_RESOURCE_ATTRIBUTE_ECC_RESERVED_2 0x00000040
+#define EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED 0x00000080
+#define EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED 0x00000100
+#define EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED 0x00000200
+#define EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE 0x00000400
+#define EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE 0x00000800
+#define EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE 0x00001000
+#define EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE 0x00002000
+#define EFI_RESOURCE_ATTRIBUTE_16_BIT_IO 0x00004000
+#define EFI_RESOURCE_ATTRIBUTE_32_BIT_IO 0x00008000
+#define EFI_RESOURCE_ATTRIBUTE_64_BIT_IO 0x00010000
+#define EFI_RESOURCE_ATTRIBUTE_UNCACHED_EXPORTED 0x00020000
+
+///
+/// Describes the resource properties of all fixed,
+/// nonrelocatable resource ranges found on the processor
+/// host bus during the HOB producer phase.
+///
+typedef struct {
+ EFI_HOB_GENERIC_HEADER Header;
+ EFI_GUID Owner;
+ EFI_RESOURCE_TYPE ResourceType;
+ EFI_RESOURCE_ATTRIBUTE_TYPE ResourceAttribute;
+ EFI_PHYSICAL_ADDRESS PhysicalStart;
+ UINT64 ResourceLength;
+} EFI_HOB_RESOURCE_DESCRIPTOR;
+
+///
+/// Allows writers of executable content in the HOB producer phase to
+/// maintain and manage HOBs with specific GUID.
+///
+typedef struct {
+ EFI_HOB_GENERIC_HEADER Header;
+ EFI_GUID Name;
+
+ ///
+ /// Guid specific data goes here
+ ///
+} EFI_HOB_GUID_TYPE;
+
+///
+/// Details the location of firmware volumes that contain firmware files.
+///
+typedef struct {
+ EFI_HOB_GENERIC_HEADER Header;
+ EFI_PHYSICAL_ADDRESS BaseAddress;
+ UINT64 Length;
+} EFI_HOB_FIRMWARE_VOLUME;
+
+///
+/// Details the location of a firmware volume which was extracted
+/// from a file within another firmware volume.
+///
+typedef struct {
+ EFI_HOB_GENERIC_HEADER Header;
+ EFI_PHYSICAL_ADDRESS BaseAddress;
+ UINT64 Length;
+ EFI_GUID FvName;
+ EFI_GUID FileName;
+} EFI_HOB_FIRMWARE_VOLUME2;
+
+
+///
+/// Describes processor information, such as address space and I/O space capabilities.
+///
+typedef struct {
+ EFI_HOB_GENERIC_HEADER Header;
+ UINT8 SizeOfMemorySpace;
+ UINT8 SizeOfIoSpace;
+ UINT8 Reserved[6];
+} EFI_HOB_CPU;
+
+
+///
+/// Describes pool memory allocations.
+///
+typedef struct {
+ EFI_HOB_GENERIC_HEADER Header;
+} EFI_HOB_MEMORY_POOL;
+
+///
+/// Union of all the possible HOB Types
+///
+typedef union {
+ EFI_HOB_GENERIC_HEADER *Header;
+ EFI_HOB_HANDOFF_INFO_TABLE *HandoffInformationTable;
+ EFI_HOB_MEMORY_ALLOCATION *MemoryAllocation;
+ EFI_HOB_MEMORY_ALLOCATION_BSP_STORE *MemoryAllocationBspStore;
+ EFI_HOB_MEMORY_ALLOCATION_STACK *MemoryAllocationStack;
+ EFI_HOB_MEMORY_ALLOCATION_MODULE *MemoryAllocationModule;
+ EFI_HOB_RESOURCE_DESCRIPTOR *ResourceDescriptor;
+ EFI_HOB_GUID_TYPE *Guid;
+ EFI_HOB_FIRMWARE_VOLUME *FirmwareVolume;
+ EFI_HOB_FIRMWARE_VOLUME2 *FirmwareVolume2;
+ EFI_HOB_CPU *Cpu;
+ EFI_HOB_MEMORY_POOL *Pool;
+ UINT8 *Raw;
+} EFI_PEI_HOB_POINTERS;
+
+
+#endif
diff --git a/gpxe/src/include/gpxe/efi/Pi/PiMultiPhase.h b/gpxe/src/include/gpxe/efi/Pi/PiMultiPhase.h
new file mode 100644
index 00000000..9ec013be
--- /dev/null
+++ b/gpxe/src/include/gpxe/efi/Pi/PiMultiPhase.h
@@ -0,0 +1,104 @@
+/** @file
+ Include file matches things in PI for multiple module types.
+
+ Copyright (c) 2006 - 2007, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+ @par Revision Reference:
+ Version 1.0.
+
+**/
+
+#ifndef __PI_MULTIPHASE_H__
+#define __PI_MULTIPHASE_H__
+
+#include <gpxe/efi/Uefi/UefiMultiPhase.h>
+
+#include <gpxe/efi/Pi/PiFirmwareVolume.h>
+#include <gpxe/efi/Pi/PiFirmwareFile.h>
+#include <gpxe/efi/Pi/PiBootMode.h>
+
+#include <gpxe/efi/Pi/PiHob.h>
+#include <gpxe/efi/Pi/PiDependency.h>
+
+
+#define EFI_NOT_AVAILABLE_YET EFIERR (32)
+
+///
+/// Status Code Type Definition
+///
+typedef UINT32 EFI_STATUS_CODE_TYPE;
+
+//
+// A Status Code Type is made up of the code type and severity
+// All values masked by EFI_STATUS_CODE_RESERVED_MASK are
+// reserved for use by this specification.
+//
+#define EFI_STATUS_CODE_TYPE_MASK 0x000000FF
+#define EFI_STATUS_CODE_SEVERITY_MASK 0xFF000000
+#define EFI_STATUS_CODE_RESERVED_MASK 0x00FFFF00
+
+//
+// Definition of code types, all other values masked by
+// EFI_STATUS_CODE_TYPE_MASK are reserved for use by
+// this specification.
+//
+#define EFI_PROGRESS_CODE 0x00000001
+#define EFI_ERROR_CODE 0x00000002
+#define EFI_DEBUG_CODE 0x00000003
+
+//
+// Definitions of severities, all other values masked by
+// EFI_STATUS_CODE_SEVERITY_MASK are reserved for use by
+// this specification.
+// Uncontained errors are major errors that could not contained
+// to the specific component that is reporting the error
+// For example, if a memory error was not detected early enough,
+// the bad data could be consumed by other drivers.
+//
+#define EFI_ERROR_MINOR 0x40000000
+#define EFI_ERROR_MAJOR 0x80000000
+#define EFI_ERROR_UNRECOVERED 0x90000000
+#define EFI_ERROR_UNCONTAINED 0xa0000000
+
+///
+/// Status Code Value Definition
+///
+typedef UINT32 EFI_STATUS_CODE_VALUE;
+
+//
+// A Status Code Value is made up of the class, subclass, and
+// an operation.
+//
+#define EFI_STATUS_CODE_CLASS_MASK 0xFF000000
+#define EFI_STATUS_CODE_SUBCLASS_MASK 0x00FF0000
+#define EFI_STATUS_CODE_OPERATION_MASK 0x0000FFFF
+
+///
+/// Definition of Status Code extended data header.
+/// The data will follow HeaderSize bytes from the beginning of
+/// the structure and is Size bytes long.
+///
+typedef struct {
+ UINT16 HeaderSize;
+ UINT16 Size;
+ EFI_GUID Type;
+} EFI_STATUS_CODE_DATA;
+
+
+//
+// Bit values for AuthenticationStatus
+//
+#define EFI_AUTH_STATUS_PLATFORM_OVERRIDE 0x01
+#define EFI_AUTH_STATUS_IMAGE_SIGNED 0x02
+#define EFI_AUTH_STATUS_NOT_TESTED 0x04
+#define EFI_AUTH_STATUS_TEST_FAILED 0x08
+#define EFI_AUTH_STATUS_ALL 0x0f
+
+#endif
diff --git a/gpxe/src/include/gpxe/efi/PiDxe.h b/gpxe/src/include/gpxe/efi/PiDxe.h
new file mode 100644
index 00000000..c3263029
--- /dev/null
+++ b/gpxe/src/include/gpxe/efi/PiDxe.h
@@ -0,0 +1,25 @@
+/** @file
+
+ Root include file for Mde Package DXE_CORE, DXE, SMM, SAL type modules.
+
+Copyright (c) 2006 - 2007, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __PI_DXE_H__
+#define __PI_DXE_H__
+
+#include <gpxe/efi/Uefi/UefiBaseType.h>
+#include <gpxe/efi/Uefi/UefiSpec.h>
+
+#include <gpxe/efi/Pi/PiDxeCis.h>
+
+#endif
+
diff --git a/gpxe/src/include/gpxe/efi/ProcessorBind.h b/gpxe/src/include/gpxe/efi/ProcessorBind.h
new file mode 100644
index 00000000..cc5a9852
--- /dev/null
+++ b/gpxe/src/include/gpxe/efi/ProcessorBind.h
@@ -0,0 +1,10 @@
+/*
+ * EFI header files rely on having the CPU architecture directory
+ * present in the search path in order to pick up ProcessorBind.h. We
+ * use this header file as a quick indirection layer.
+ * - mcb30
+ */
+
+#if __i386__
+#include <gpxe/efi/Ia32/ProcessorBind.h>
+#endif
diff --git a/gpxe/src/include/gpxe/efi/Protocol/Cpu.h b/gpxe/src/include/gpxe/efi/Protocol/Cpu.h
new file mode 100644
index 00000000..6052a34f
--- /dev/null
+++ b/gpxe/src/include/gpxe/efi/Protocol/Cpu.h
@@ -0,0 +1,326 @@
+/** @file
+ CPU Architectural Protocol as defined in PI spec Volume 2 DXE
+
+ This code abstracts the DXE core from processor implementation details.
+
+ Copyright (c) 2006 - 2008, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __ARCH_PROTOCOL_CPU_H__
+#define __ARCH_PROTOCOL_CPU_H__
+
+#include <gpxe/efi/Protocol/DebugSupport.h>
+
+#define EFI_CPU_ARCH_PROTOCOL_GUID \
+ { 0x26baccb1, 0x6f42, 0x11d4, {0xbc, 0xe7, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81 } }
+
+typedef struct _EFI_CPU_ARCH_PROTOCOL EFI_CPU_ARCH_PROTOCOL;
+
+typedef enum {
+ EfiCpuFlushTypeWriteBackInvalidate,
+ EfiCpuFlushTypeWriteBack,
+ EfiCpuFlushTypeInvalidate,
+ EfiCpuMaxFlushType
+} EFI_CPU_FLUSH_TYPE;
+
+typedef enum {
+ EfiCpuInit,
+ EfiCpuMaxInitType
+} EFI_CPU_INIT_TYPE;
+
+/**
+ EFI_CPU_INTERRUPT_HANDLER that is called when a processor interrupt occurs.
+
+ @param InterruptType Defines the type of interrupt or exception that
+ occurred on the processor.This parameter is processor architecture specific.
+ @param SystemContext A pointer to the processor context when
+ the interrupt occurred on the processor.
+
+ @return None
+
+**/
+typedef
+VOID
+(EFIAPI *EFI_CPU_INTERRUPT_HANDLER)(
+ IN CONST EFI_EXCEPTION_TYPE InterruptType,
+ IN CONST EFI_SYSTEM_CONTEXT SystemContext
+ );
+
+/**
+ This function flushes the range of addresses from Start to Start+Length
+ from the processor's data cache. If Start is not aligned to a cache line
+ boundary, then the bytes before Start to the preceding cache line boundary
+ are also flushed. If Start+Length is not aligned to a cache line boundary,
+ then the bytes past Start+Length to the end of the next cache line boundary
+ are also flushed. The FlushType of EfiCpuFlushTypeWriteBackInvalidate must be
+ supported. If the data cache is fully coherent with all DMA operations, then
+ this function can just return EFI_SUCCESS. If the processor does not support
+ flushing a range of the data cache, then the entire data cache can be flushed.
+
+ @param This The EFI_CPU_ARCH_PROTOCOL instance.
+ @param Start The beginning physical address to flush from the processor's data
+ cache.
+ @param Length The number of bytes to flush from the processor's data cache. This
+ function may flush more bytes than Length specifies depending upon
+ the granularity of the flush operation that the processor supports.
+ @param FlushType Specifies the type of flush operation to perform.
+
+ @retval EFI_SUCCESS The address range from Start to Start+Length was flushed from
+ the processor's data cache.
+ @retval EFI_UNSUPPORTEDT The processor does not support the cache flush type specified
+ by FlushType.
+ @retval EFI_DEVICE_ERROR The address range from Start to Start+Length could not be flushed
+ from the processor's data cache.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_CPU_FLUSH_DATA_CACHE)(
+ IN EFI_CPU_ARCH_PROTOCOL *This,
+ IN EFI_PHYSICAL_ADDRESS Start,
+ IN UINT64 Length,
+ IN EFI_CPU_FLUSH_TYPE FlushType
+ );
+
+
+/**
+ This function enables interrupt processing by the processor.
+
+ @param This The EFI_CPU_ARCH_PROTOCOL instance.
+
+ @retval EFI_SUCCESS Interrupts are enabled on the processor.
+ @retval EFI_DEVICE_ERROR Interrupts could not be enabled on the processor.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_CPU_ENABLE_INTERRUPT)(
+ IN EFI_CPU_ARCH_PROTOCOL *This
+ );
+
+
+/**
+ This function disables interrupt processing by the processor.
+
+ @param This The EFI_CPU_ARCH_PROTOCOL instance.
+
+ @retval EFI_SUCCESS Interrupts are disabled on the processor.
+ @retval EFI_DEVICE_ERROR Interrupts could not be disabled on the processor.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_CPU_DISABLE_INTERRUPT)(
+ IN EFI_CPU_ARCH_PROTOCOL *This
+ );
+
+
+/**
+ This function retrieves the processor's current interrupt state a returns it in
+ State. If interrupts are currently enabled, then TRUE is returned. If interrupts
+ are currently disabled, then FALSE is returned.
+
+ @param This The EFI_CPU_ARCH_PROTOCOL instance.
+ @param State A pointer to the processor's current interrupt state. Set to TRUE if
+ interrupts are enabled and FALSE if interrupts are disabled.
+
+ @retval EFI_SUCCESS The processor's current interrupt state was returned in State.
+ @retval EFI_INVALID_PARAMETER State is NULL.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_CPU_GET_INTERRUPT_STATE)(
+ IN EFI_CPU_ARCH_PROTOCOL *This,
+ OUT BOOLEAN *State
+ );
+
+
+/**
+ This function generates an INIT on the processor. If this function succeeds, then the
+ processor will be reset, and control will not be returned to the caller. If InitType is
+ not supported by this processor, or the processor cannot programmatically generate an
+ INIT without help from external hardware, then EFI_UNSUPPORTED is returned. If an error
+ occurs attempting to generate an INIT, then EFI_DEVICE_ERROR is returned.
+
+ @param This The EFI_CPU_ARCH_PROTOCOL instance.
+ @param InitType The type of processor INIT to perform.
+
+ @retval EFI_SUCCESS The processor INIT was performed. This return code should never be seen.
+ @retval EFI_UNSUPPORTED The processor INIT operation specified by InitType is not supported
+ by this processor.
+ @retval EFI_DEVICE_ERROR The processor INIT failed.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_CPU_INIT)(
+ IN EFI_CPU_ARCH_PROTOCOL *This,
+ IN EFI_CPU_INIT_TYPE InitType
+ );
+
+
+/**
+ This function registers and enables the handler specified by InterruptHandler for a processor
+ interrupt or exception type specified by InterruptType. If InterruptHandler is NULL, then the
+ handler for the processor interrupt or exception type specified by InterruptType is uninstalled.
+ The installed handler is called once for each processor interrupt or exception.
+
+ @param This The EFI_CPU_ARCH_PROTOCOL instance.
+ @param InterruptType A pointer to the processor's current interrupt state. Set to TRUE if interrupts
+ are enabled and FALSE if interrupts are disabled.
+ @param InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER that is called
+ when a processor interrupt occurs. If this parameter is NULL, then the handler
+ will be uninstalled.
+
+ @retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled.
+ @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InterruptType was
+ previously installed.
+ @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not
+ previously installed.
+ @retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_CPU_REGISTER_INTERRUPT_HANDLER)(
+ IN EFI_CPU_ARCH_PROTOCOL *This,
+ IN EFI_EXCEPTION_TYPE InterruptType,
+ IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler
+ );
+
+
+/**
+ This function reads the processor timer specified by TimerIndex and returns it in TimerValue.
+
+ @param This The EFI_CPU_ARCH_PROTOCOL instance.
+ @param TimerIndex Specifies which processor timer is to be returned in TimerValue. This parameter
+ must be between 0 and NumberOfTimers-1.
+ @param TimerValue Pointer to the returned timer value.
+ @param TimerPeriod A pointer to the amount of time that passes in femtoseconds for each increment
+ of TimerValue.
+
+ @retval EFI_SUCCESS The processor timer value specified by TimerIndex was returned in TimerValue.
+ @retval EFI_DEVICE_ERROR An error occurred attempting to read one of the processor's timers.
+ @retval EFI_INVALID_PARAMETER TimerValue is NULL or TimerIndex is not valid.
+ @retval EFI_UNSUPPORTED The processor does not have any readable timers.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_CPU_GET_TIMER_VALUE)(
+ IN EFI_CPU_ARCH_PROTOCOL *This,
+ IN UINT32 TimerIndex,
+ OUT UINT64 *TimerValue,
+ OUT UINT64 *TimerPeriod OPTIONAL
+ );
+
+
+/**
+ This function modifies the attributes for the memory region specified by BaseAddress and
+ Length from their current attributes to the attributes specified by Attributes.
+
+ @param This The EFI_CPU_ARCH_PROTOCOL instance.
+ @param BaseAddress The physical address that is the start address of a memory region.
+ @param Length The size in bytes of the memory region.
+ @param Attributes The bit mask of attributes to set for the memory region.
+
+ @retval EFI_SUCCESS The attributes were set for the memory region.
+ @retval EFI_ACCESS_DENIED The attributes for the memory resource range specified by
+ BaseAddress and Length cannot be modified.
+ @retval EFI_INVALID_PARAMETER Length is zero.
+ @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
+ the memory resource range.
+ @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory
+ resource range specified by BaseAddress and Length.
+ The bit mask of attributes is not support for the memory resource
+ range specified by BaseAddress and Length.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_CPU_SET_MEMORY_ATTRIBUTES)(
+ IN EFI_CPU_ARCH_PROTOCOL *This,
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN UINT64 Attributes
+ );
+
+
+/**
+ @par Protocol Description:
+ The EFI_CPU_ARCH_PROTOCOL is used to abstract processor-specific functions from the DXE
+ Foundation. This includes flushing caches, enabling and disabling interrupts, hooking interrupt
+ vectors and exception vectors, reading internal processor timers, resetting the processor, and
+ determining the processor frequency.
+
+ @param FlushDataCache
+ Flushes a range of the processor's data cache. If the processor does
+ not contain a data cache, or the data cache is fully coherent, then this
+ function can just return EFI_SUCCESS. If the processor does not support
+ flushing a range of addresses from the data cache, then the entire data
+ cache must be flushed.
+
+ @param EnableInterrupt
+ Enables interrupt processing by the processor.
+
+ @param DisableInterrupt
+ Disables interrupt processing by the processor.
+
+ @param GetInterruptState
+ Retrieves the processor's current interrupt state.
+
+ @param Init
+ Generates an INIT on the processor. If a processor cannot programmatically
+ generate an INIT without help from external hardware, then this function
+ returns EFI_UNSUPPORTED.
+
+ @param RegisterInterruptHandler
+ Associates an interrupt service routine with one of the processor's interrupt
+ vectors. This function is typically used by the EFI_TIMER_ARCH_PROTOCOL to
+ hook the timer interrupt in a system. It can also be used by the debugger to
+ hook exception vectors.
+
+ @param GetTimerValue
+ Returns the value of one of the processor's internal timers.
+
+ @param SetMemoryAttributes
+ Attempts to set the attributes of a memory region.
+
+ @param NumberOfTimers
+ The number of timers that are available in a processor. The value in this
+ field is a constant that must not be modified after the CPU Architectural
+ Protocol is installed. All consumers must treat this as a read-only field.
+
+ @param DmaBufferAlignment
+ The size, in bytes, of the alignment required for DMA buffer allocations.
+ This is typically the size of the largest data cache line in the platform.
+ The value in this field is a constant that must not be modified after the
+ CPU Architectural Protocol is installed. All consumers must treat this as
+ a read-only field.
+
+**/
+struct _EFI_CPU_ARCH_PROTOCOL {
+ EFI_CPU_FLUSH_DATA_CACHE FlushDataCache;
+ EFI_CPU_ENABLE_INTERRUPT EnableInterrupt;
+ EFI_CPU_DISABLE_INTERRUPT DisableInterrupt;
+ EFI_CPU_GET_INTERRUPT_STATE GetInterruptState;
+ EFI_CPU_INIT Init;
+ EFI_CPU_REGISTER_INTERRUPT_HANDLER RegisterInterruptHandler;
+ EFI_CPU_GET_TIMER_VALUE GetTimerValue;
+ EFI_CPU_SET_MEMORY_ATTRIBUTES SetMemoryAttributes;
+ UINT32 NumberOfTimers;
+ UINT32 DmaBufferAlignment;
+};
+
+extern EFI_GUID gEfiCpuArchProtocolGuid;
+
+#endif
diff --git a/gpxe/src/include/gpxe/efi/Protocol/CpuIo.h b/gpxe/src/include/gpxe/efi/Protocol/CpuIo.h
new file mode 100644
index 00000000..8d35c6cd
--- /dev/null
+++ b/gpxe/src/include/gpxe/efi/Protocol/CpuIo.h
@@ -0,0 +1,128 @@
+/** @file
+ This code abstracts the CPU IO Protocol which installed by some platform or chipset-specific
+ PEIM that abstracts the processor-visible I/O operations.
+
+ Copyright (c) 2007, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+ Module Name: CpuIO.h
+
+ @par Revision Reference:
+ CPU IO Protocol is defined in Framework of EFI CPU IO Protocol Spec
+ Version 0.9
+
+**/
+
+#ifndef _CPUIO_H_
+#define _CPUIO_H_
+
+#include <gpxe/efi/PiDxe.h>
+
+#define EFI_CPU_IO_PROTOCOL_GUID \
+ { \
+ 0xB0732526, 0x38C8, 0x4b40, {0x88, 0x77, 0x61, 0xC7, 0xB0, 0x6A, 0xAC, 0x45 } \
+ }
+
+typedef struct _EFI_CPU_IO_PROTOCOL EFI_CPU_IO_PROTOCOL;
+
+//
+// *******************************************************
+// EFI_CPU_IO_PROTOCOL_WIDTH
+// *******************************************************
+//
+typedef enum {
+ EfiCpuIoWidthUint8,
+ EfiCpuIoWidthUint16,
+ EfiCpuIoWidthUint32,
+ EfiCpuIoWidthUint64,
+ EfiCpuIoWidthFifoUint8,
+ EfiCpuIoWidthFifoUint16,
+ EfiCpuIoWidthFifoUint32,
+ EfiCpuIoWidthFifoUint64,
+ EfiCpuIoWidthFillUint8,
+ EfiCpuIoWidthFillUint16,
+ EfiCpuIoWidthFillUint32,
+ EfiCpuIoWidthFillUint64,
+ EfiCpuIoWidthMaximum
+} EFI_CPU_IO_PROTOCOL_WIDTH;
+
+//
+// *******************************************************
+// EFI_CPU_IO_PROTOCOL_IO_MEM
+// *******************************************************
+//
+/**
+ Enables a driver to access memory-mapped registers in the EFI system memory space.
+ Or, Enables a driver to access registers in the EFI CPU I/O space.
+
+ @param This A pointer to the EFI_CPU_IO_PROTOCOL instance.
+ @param Width Signifies the width of the I/O or Memory operation.
+ @param Address The base address of the I/O or Memoryoperation.
+ @param Count The number of I/O or Memory operations to perform.
+ The number of bytes moved is Width size * Count, starting at Address.
+ @param Buffer For read operations, the destination buffer to store the results.
+ For write operations, the source buffer from which to write data.
+
+ @retval EFI_SUCCESS The data was read from or written to the EFI system.
+ @retval EFI_INVALID_PARAMETER Width is invalid for this EFI system.Or Buffer is NULL.
+ @retval EFI_UNSUPPORTED The Buffer is not aligned for the given Width.
+ Or,The address range specified by Address, Width, and Count is not valid for this EFI system.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_CPU_IO_PROTOCOL_IO_MEM)(
+ IN EFI_CPU_IO_PROTOCOL *This,
+ IN EFI_CPU_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ );
+
+//
+// *******************************************************
+// EFI_CPU_IO_PROTOCOL_ACCESS
+// *******************************************************
+//
+typedef struct {
+ EFI_CPU_IO_PROTOCOL_IO_MEM Read;
+ EFI_CPU_IO_PROTOCOL_IO_MEM Write;
+} EFI_CPU_IO_PROTOCOL_ACCESS;
+
+//
+// *******************************************************
+// EFI_CPU_IO_PROTOCOL
+// *******************************************************
+//
+/**
+ @par Protocol Description:
+ Provides the basic memory and I/O interfaces that are used to abstract
+ accesses to devices in a system.
+
+ @param Mem.Read
+ Allows reads from memory-mapped I/O space.
+
+ @param Mem.Write
+ Allows writes to memory-mapped I/O space.
+
+ @param Io.Read
+ Allows reads from I/O space.
+
+ @param Io.Write
+ Allows writes to I/O space.
+
+**/
+struct _EFI_CPU_IO_PROTOCOL {
+ EFI_CPU_IO_PROTOCOL_ACCESS Mem;
+ EFI_CPU_IO_PROTOCOL_ACCESS Io;
+};
+
+extern EFI_GUID gEfiCpuIoProtocolGuid;
+
+#endif
diff --git a/gpxe/src/include/gpxe/efi/Protocol/DebugSupport.h b/gpxe/src/include/gpxe/efi/Protocol/DebugSupport.h
new file mode 100644
index 00000000..6f785a17
--- /dev/null
+++ b/gpxe/src/include/gpxe/efi/Protocol/DebugSupport.h
@@ -0,0 +1,656 @@
+/** @file
+ DebugSupport protocol and supporting definitions as defined in the UEFI2.0
+ specification.
+
+ The DebugSupport protocol is used by source level debuggers to abstract the
+ processor and handle context save and restore operations.
+
+ Copyright (c) 2006 - 2008, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __DEBUG_SUPPORT_H__
+#define __DEBUG_SUPPORT_H__
+
+#include <gpxe/efi/ProcessorBind.h>
+#include <gpxe/efi/IndustryStandard/PeImage.h>
+
+typedef struct _EFI_DEBUG_SUPPORT_PROTOCOL EFI_DEBUG_SUPPORT_PROTOCOL;
+
+///
+/// Debug Support protocol {2755590C-6F3C-42FA-9EA4-A3BA543CDA25}
+///
+#define EFI_DEBUG_SUPPORT_PROTOCOL_GUID \
+ { \
+ 0x2755590C, 0x6F3C, 0x42FA, {0x9E, 0xA4, 0xA3, 0xBA, 0x54, 0x3C, 0xDA, 0x25 } \
+ }
+
+///
+/// Debug Support definitions
+///
+typedef INTN EFI_EXCEPTION_TYPE;
+
+//
+// IA-32 processor exception types
+//
+#define EXCEPT_IA32_DIVIDE_ERROR 0
+#define EXCEPT_IA32_DEBUG 1
+#define EXCEPT_IA32_NMI 2
+#define EXCEPT_IA32_BREAKPOINT 3
+#define EXCEPT_IA32_OVERFLOW 4
+#define EXCEPT_IA32_BOUND 5
+#define EXCEPT_IA32_INVALID_OPCODE 6
+#define EXCEPT_IA32_DOUBLE_FAULT 8
+#define EXCEPT_IA32_INVALID_TSS 10
+#define EXCEPT_IA32_SEG_NOT_PRESENT 11
+#define EXCEPT_IA32_STACK_FAULT 12
+#define EXCEPT_IA32_GP_FAULT 13
+#define EXCEPT_IA32_PAGE_FAULT 14
+#define EXCEPT_IA32_FP_ERROR 16
+#define EXCEPT_IA32_ALIGNMENT_CHECK 17
+#define EXCEPT_IA32_MACHINE_CHECK 18
+#define EXCEPT_IA32_SIMD 19
+
+//
+// IA-32 processor context definition
+//
+//
+// FXSAVE_STATE
+// FP / MMX / XMM registers (see fxrstor instruction definition)
+//
+typedef struct {
+ UINT16 Fcw;
+ UINT16 Fsw;
+ UINT16 Ftw;
+ UINT16 Opcode;
+ UINT32 Eip;
+ UINT16 Cs;
+ UINT16 Reserved1;
+ UINT32 DataOffset;
+ UINT16 Ds;
+ UINT8 Reserved2[10];
+ UINT8 St0Mm0[10], Reserved3[6];
+ UINT8 St1Mm1[10], Reserved4[6];
+ UINT8 St2Mm2[10], Reserved5[6];
+ UINT8 St3Mm3[10], Reserved6[6];
+ UINT8 St4Mm4[10], Reserved7[6];
+ UINT8 St5Mm5[10], Reserved8[6];
+ UINT8 St6Mm6[10], Reserved9[6];
+ UINT8 St7Mm7[10], Reserved10[6];
+ UINT8 Xmm0[16];
+ UINT8 Xmm1[16];
+ UINT8 Xmm2[16];
+ UINT8 Xmm3[16];
+ UINT8 Xmm4[16];
+ UINT8 Xmm5[16];
+ UINT8 Xmm6[16];
+ UINT8 Xmm7[16];
+ UINT8 Reserved11[14 * 16];
+} EFI_FX_SAVE_STATE_IA32;
+
+typedef struct {
+ UINT32 ExceptionData;
+ EFI_FX_SAVE_STATE_IA32 FxSaveState;
+ UINT32 Dr0;
+ UINT32 Dr1;
+ UINT32 Dr2;
+ UINT32 Dr3;
+ UINT32 Dr6;
+ UINT32 Dr7;
+ UINT32 Cr0;
+ UINT32 Cr1; /* Reserved */
+ UINT32 Cr2;
+ UINT32 Cr3;
+ UINT32 Cr4;
+ UINT32 Eflags;
+ UINT32 Ldtr;
+ UINT32 Tr;
+ UINT32 Gdtr[2];
+ UINT32 Idtr[2];
+ UINT32 Eip;
+ UINT32 Gs;
+ UINT32 Fs;
+ UINT32 Es;
+ UINT32 Ds;
+ UINT32 Cs;
+ UINT32 Ss;
+ UINT32 Edi;
+ UINT32 Esi;
+ UINT32 Ebp;
+ UINT32 Esp;
+ UINT32 Ebx;
+ UINT32 Edx;
+ UINT32 Ecx;
+ UINT32 Eax;
+} EFI_SYSTEM_CONTEXT_IA32;
+
+//
+// X64 processor exception types
+//
+#define EXCEPT_X64_DIVIDE_ERROR 0
+#define EXCEPT_X64_DEBUG 1
+#define EXCEPT_X64_NMI 2
+#define EXCEPT_X64_BREAKPOINT 3
+#define EXCEPT_X64_OVERFLOW 4
+#define EXCEPT_X64_BOUND 5
+#define EXCEPT_X64_INVALID_OPCODE 6
+#define EXCEPT_X64_DOUBLE_FAULT 8
+#define EXCEPT_X64_INVALID_TSS 10
+#define EXCEPT_X64_SEG_NOT_PRESENT 11
+#define EXCEPT_X64_STACK_FAULT 12
+#define EXCEPT_X64_GP_FAULT 13
+#define EXCEPT_X64_PAGE_FAULT 14
+#define EXCEPT_X64_FP_ERROR 16
+#define EXCEPT_X64_ALIGNMENT_CHECK 17
+#define EXCEPT_X64_MACHINE_CHECK 18
+#define EXCEPT_X64_SIMD 19
+
+//
+// X64 processor context definition
+//
+// FXSAVE_STATE
+// FP / MMX / XMM registers (see fxrstor instruction definition)
+//
+typedef struct {
+ UINT16 Fcw;
+ UINT16 Fsw;
+ UINT16 Ftw;
+ UINT16 Opcode;
+ UINT64 Rip;
+ UINT64 DataOffset;
+ UINT8 Reserved1[8];
+ UINT8 St0Mm0[10], Reserved2[6];
+ UINT8 St1Mm1[10], Reserved3[6];
+ UINT8 St2Mm2[10], Reserved4[6];
+ UINT8 St3Mm3[10], Reserved5[6];
+ UINT8 St4Mm4[10], Reserved6[6];
+ UINT8 St5Mm5[10], Reserved7[6];
+ UINT8 St6Mm6[10], Reserved8[6];
+ UINT8 St7Mm7[10], Reserved9[6];
+ UINT8 Xmm0[16];
+ UINT8 Xmm1[16];
+ UINT8 Xmm2[16];
+ UINT8 Xmm3[16];
+ UINT8 Xmm4[16];
+ UINT8 Xmm5[16];
+ UINT8 Xmm6[16];
+ UINT8 Xmm7[16];
+ //
+ // NOTE: UEFI 2.0 spec definition as follows.
+ //
+ UINT8 Reserved11[14 * 16];
+} EFI_FX_SAVE_STATE_X64;
+
+typedef struct {
+ UINT64 ExceptionData;
+ EFI_FX_SAVE_STATE_X64 FxSaveState;
+ UINT64 Dr0;
+ UINT64 Dr1;
+ UINT64 Dr2;
+ UINT64 Dr3;
+ UINT64 Dr6;
+ UINT64 Dr7;
+ UINT64 Cr0;
+ UINT64 Cr1; /* Reserved */
+ UINT64 Cr2;
+ UINT64 Cr3;
+ UINT64 Cr4;
+ UINT64 Cr8;
+ UINT64 Rflags;
+ UINT64 Ldtr;
+ UINT64 Tr;
+ UINT64 Gdtr[2];
+ UINT64 Idtr[2];
+ UINT64 Rip;
+ UINT64 Gs;
+ UINT64 Fs;
+ UINT64 Es;
+ UINT64 Ds;
+ UINT64 Cs;
+ UINT64 Ss;
+ UINT64 Rdi;
+ UINT64 Rsi;
+ UINT64 Rbp;
+ UINT64 Rsp;
+ UINT64 Rbx;
+ UINT64 Rdx;
+ UINT64 Rcx;
+ UINT64 Rax;
+ UINT64 R8;
+ UINT64 R9;
+ UINT64 R10;
+ UINT64 R11;
+ UINT64 R12;
+ UINT64 R13;
+ UINT64 R14;
+ UINT64 R15;
+} EFI_SYSTEM_CONTEXT_X64;
+
+//
+// IPF processor exception types
+//
+#define EXCEPT_IPF_VHTP_TRANSLATION 0
+#define EXCEPT_IPF_INSTRUCTION_TLB 1
+#define EXCEPT_IPF_DATA_TLB 2
+#define EXCEPT_IPF_ALT_INSTRUCTION_TLB 3
+#define EXCEPT_IPF_ALT_DATA_TLB 4
+#define EXCEPT_IPF_DATA_NESTED_TLB 5
+#define EXCEPT_IPF_INSTRUCTION_KEY_MISSED 6
+#define EXCEPT_IPF_DATA_KEY_MISSED 7
+#define EXCEPT_IPF_DIRTY_BIT 8
+#define EXCEPT_IPF_INSTRUCTION_ACCESS_BIT 9
+#define EXCEPT_IPF_DATA_ACCESS_BIT 10
+#define EXCEPT_IPF_BREAKPOINT 11
+#define EXCEPT_IPF_EXTERNAL_INTERRUPT 12
+//
+// 13 - 19 reserved
+//
+#define EXCEPT_IPF_PAGE_NOT_PRESENT 20
+#define EXCEPT_IPF_KEY_PERMISSION 21
+#define EXCEPT_IPF_INSTRUCTION_ACCESS_RIGHTS 22
+#define EXCEPT_IPF_DATA_ACCESS_RIGHTS 23
+#define EXCEPT_IPF_GENERAL_EXCEPTION 24
+#define EXCEPT_IPF_DISABLED_FP_REGISTER 25
+#define EXCEPT_IPF_NAT_CONSUMPTION 26
+#define EXCEPT_IPF_SPECULATION 27
+//
+// 28 reserved
+//
+#define EXCEPT_IPF_DEBUG 29
+#define EXCEPT_IPF_UNALIGNED_REFERENCE 30
+#define EXCEPT_IPF_UNSUPPORTED_DATA_REFERENCE 31
+#define EXCEPT_IPF_FP_FAULT 32
+#define EXCEPT_IPF_FP_TRAP 33
+#define EXCEPT_IPF_LOWER_PRIVILEGE_TRANSFER_TRAP 34
+#define EXCEPT_IPF_TAKEN_BRANCH 35
+#define EXCEPT_IPF_SINGLE_STEP 36
+//
+// 37 - 44 reserved
+//
+#define EXCEPT_IPF_IA32_EXCEPTION 45
+#define EXCEPT_IPF_IA32_INTERCEPT 46
+#define EXCEPT_IPF_IA32_INTERRUPT 47
+
+//
+// IPF processor context definition
+//
+typedef struct {
+ //
+ // The first reserved field is necessary to preserve alignment for the correct
+ // bits in UNAT and to insure F2 is 16 byte aligned..
+ //
+ UINT64 Reserved;
+ UINT64 R1;
+ UINT64 R2;
+ UINT64 R3;
+ UINT64 R4;
+ UINT64 R5;
+ UINT64 R6;
+ UINT64 R7;
+ UINT64 R8;
+ UINT64 R9;
+ UINT64 R10;
+ UINT64 R11;
+ UINT64 R12;
+ UINT64 R13;
+ UINT64 R14;
+ UINT64 R15;
+ UINT64 R16;
+ UINT64 R17;
+ UINT64 R18;
+ UINT64 R19;
+ UINT64 R20;
+ UINT64 R21;
+ UINT64 R22;
+ UINT64 R23;
+ UINT64 R24;
+ UINT64 R25;
+ UINT64 R26;
+ UINT64 R27;
+ UINT64 R28;
+ UINT64 R29;
+ UINT64 R30;
+ UINT64 R31;
+
+ UINT64 F2[2];
+ UINT64 F3[2];
+ UINT64 F4[2];
+ UINT64 F5[2];
+ UINT64 F6[2];
+ UINT64 F7[2];
+ UINT64 F8[2];
+ UINT64 F9[2];
+ UINT64 F10[2];
+ UINT64 F11[2];
+ UINT64 F12[2];
+ UINT64 F13[2];
+ UINT64 F14[2];
+ UINT64 F15[2];
+ UINT64 F16[2];
+ UINT64 F17[2];
+ UINT64 F18[2];
+ UINT64 F19[2];
+ UINT64 F20[2];
+ UINT64 F21[2];
+ UINT64 F22[2];
+ UINT64 F23[2];
+ UINT64 F24[2];
+ UINT64 F25[2];
+ UINT64 F26[2];
+ UINT64 F27[2];
+ UINT64 F28[2];
+ UINT64 F29[2];
+ UINT64 F30[2];
+ UINT64 F31[2];
+
+ UINT64 Pr;
+
+ UINT64 B0;
+ UINT64 B1;
+ UINT64 B2;
+ UINT64 B3;
+ UINT64 B4;
+ UINT64 B5;
+ UINT64 B6;
+ UINT64 B7;
+
+ //
+ // application registers
+ //
+ UINT64 ArRsc;
+ UINT64 ArBsp;
+ UINT64 ArBspstore;
+ UINT64 ArRnat;
+
+ UINT64 ArFcr;
+
+ UINT64 ArEflag;
+ UINT64 ArCsd;
+ UINT64 ArSsd;
+ UINT64 ArCflg;
+ UINT64 ArFsr;
+ UINT64 ArFir;
+ UINT64 ArFdr;
+
+ UINT64 ArCcv;
+
+ UINT64 ArUnat;
+
+ UINT64 ArFpsr;
+
+ UINT64 ArPfs;
+ UINT64 ArLc;
+ UINT64 ArEc;
+
+ //
+ // control registers
+ //
+ UINT64 CrDcr;
+ UINT64 CrItm;
+ UINT64 CrIva;
+ UINT64 CrPta;
+ UINT64 CrIpsr;
+ UINT64 CrIsr;
+ UINT64 CrIip;
+ UINT64 CrIfa;
+ UINT64 CrItir;
+ UINT64 CrIipa;
+ UINT64 CrIfs;
+ UINT64 CrIim;
+ UINT64 CrIha;
+
+ //
+ // debug registers
+ //
+ UINT64 Dbr0;
+ UINT64 Dbr1;
+ UINT64 Dbr2;
+ UINT64 Dbr3;
+ UINT64 Dbr4;
+ UINT64 Dbr5;
+ UINT64 Dbr6;
+ UINT64 Dbr7;
+
+ UINT64 Ibr0;
+ UINT64 Ibr1;
+ UINT64 Ibr2;
+ UINT64 Ibr3;
+ UINT64 Ibr4;
+ UINT64 Ibr5;
+ UINT64 Ibr6;
+ UINT64 Ibr7;
+
+ //
+ // virtual registers - nat bits for R1-R31
+ //
+ UINT64 IntNat;
+
+} EFI_SYSTEM_CONTEXT_IPF;
+
+//
+// EBC processor exception types
+//
+#define EXCEPT_EBC_UNDEFINED 0
+#define EXCEPT_EBC_DIVIDE_ERROR 1
+#define EXCEPT_EBC_DEBUG 2
+#define EXCEPT_EBC_BREAKPOINT 3
+#define EXCEPT_EBC_OVERFLOW 4
+#define EXCEPT_EBC_INVALID_OPCODE 5 // opcode out of range
+#define EXCEPT_EBC_STACK_FAULT 6
+#define EXCEPT_EBC_ALIGNMENT_CHECK 7
+#define EXCEPT_EBC_INSTRUCTION_ENCODING 8 // malformed instruction
+#define EXCEPT_EBC_BAD_BREAK 9 // BREAK 0 or undefined BREAK
+#define EXCEPT_EBC_STEP 10 // to support debug stepping
+///
+/// For coding convenience, define the maximum valid EBC exception.
+///
+#define MAX_EBC_EXCEPTION EXCEPT_EBC_STEP
+
+///
+/// EBC processor context definition
+///
+typedef struct {
+ UINT64 R0;
+ UINT64 R1;
+ UINT64 R2;
+ UINT64 R3;
+ UINT64 R4;
+ UINT64 R5;
+ UINT64 R6;
+ UINT64 R7;
+ UINT64 Flags;
+ UINT64 ControlFlags;
+ UINT64 Ip;
+} EFI_SYSTEM_CONTEXT_EBC;
+
+///
+/// Universal EFI_SYSTEM_CONTEXT definition
+///
+typedef union {
+ EFI_SYSTEM_CONTEXT_EBC *SystemContextEbc;
+ EFI_SYSTEM_CONTEXT_IA32 *SystemContextIa32;
+ EFI_SYSTEM_CONTEXT_X64 *SystemContextX64;
+ EFI_SYSTEM_CONTEXT_IPF *SystemContextIpf;
+} EFI_SYSTEM_CONTEXT;
+
+//
+// DebugSupport callback function prototypes
+//
+
+/**
+ Registers and enables an exception callback function for the specified exception.
+
+ @param ExceptionType Exception types in EBC, IA-32, X64, or IPF
+ @param SystemContext Exception content.
+
+**/
+typedef
+VOID
+(*EFI_EXCEPTION_CALLBACK)(
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ );
+
+/**
+ Registers and enables the on-target debug agent's periodic entry point.
+
+ @param SystemContext Exception content.
+
+**/
+typedef
+VOID
+(*EFI_PERIODIC_CALLBACK)(
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ );
+
+//
+// Machine type definition
+//
+typedef enum {
+ IsaIa32 = IMAGE_FILE_MACHINE_I386, // 0x014C
+ IsaX64 = IMAGE_FILE_MACHINE_X64, // 0x8664
+ IsaIpf = IMAGE_FILE_MACHINE_IA64, // 0x0200
+ IsaEbc = IMAGE_FILE_MACHINE_EBC // 0x0EBC
+} EFI_INSTRUCTION_SET_ARCHITECTURE;
+
+
+//
+// DebugSupport member function definitions
+//
+
+/**
+ Returns the maximum value that may be used for the ProcessorIndex parameter in
+ RegisterPeriodicCallback() and RegisterExceptionCallback().
+
+ @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL instance.
+ @param MaxProcessorIndex Pointer to a caller-allocated UINTN in which the maximum supported
+ processor index is returned.
+
+ @retval EFI_SUCCESS The function completed successfully.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_GET_MAXIMUM_PROCESSOR_INDEX)(
+ IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
+ OUT UINTN *MaxProcessorIndex
+ );
+
+/**
+ Registers a function to be called back periodically in interrupt context.
+
+ @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL instance.
+ @param ProcessorIndex Specifies which processor the callback function applies to.
+ @param PeriodicCallback A pointer to a function of type PERIODIC_CALLBACK that is the main
+ periodic entry point of the debug agent.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ALREADY_STARTED Non-NULL PeriodicCallback parameter when a callback
+ function was previously registered.
+ @retval EFI_OUT_OF_RESOURCES System has insufficient memory resources to register new callback
+ function.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_REGISTER_PERIODIC_CALLBACK)(
+ IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
+ IN UINTN ProcessorIndex,
+ IN EFI_PERIODIC_CALLBACK PeriodicCallback
+ );
+
+/**
+ Registers a function to be called when a given processor exception occurs.
+
+ @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL instance.
+ @param ProcessorIndex Specifies which processor the callback function applies to.
+ @param PeriodicCallback A pointer to a function of type EXCEPTION_CALLBACK that is called
+ when the processor exception specified by ExceptionType occurs.
+ @param ExceptionType Specifies which processor exception to hook.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ALREADY_STARTED Non-NULL PeriodicCallback parameter when a callback
+ function was previously registered.
+ @retval EFI_OUT_OF_RESOURCES System has insufficient memory resources to register new callback
+ function.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_REGISTER_EXCEPTION_CALLBACK)(
+ IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
+ IN UINTN ProcessorIndex,
+ IN EFI_EXCEPTION_CALLBACK ExceptionCallback,
+ IN EFI_EXCEPTION_TYPE ExceptionType
+ );
+
+/**
+ Invalidates processor instruction cache for a memory range. Subsequent execution in this range
+ causes a fresh memory fetch to retrieve code to be executed.
+
+ @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL instance.
+ @param ProcessorIndex Specifies which processor's instruction cache is to be invalidated.
+ @param Start Specifies the physical base of the memory range to be invalidated.
+ @param Length Specifies the minimum number of bytes in the processor's instruction
+ cache to invalidate.
+
+ @retval EFI_SUCCESS The function completed successfully.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_INVALIDATE_INSTRUCTION_CACHE)(
+ IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
+ IN UINTN ProcessorIndex,
+ IN VOID *Start,
+ IN UINT64 Length
+ );
+
+//
+// DebugSupport protocol definition
+//
+/**
+ @par Protocol Description:
+ This protocol provides the services to allow the debug agent to register
+ callback functions that are called either periodically or when specific
+ processor exceptions occur.
+
+ @param Isa
+ Declares the processor architecture for this instance of the EFI
+ Debug Support protocol.
+
+ @param GetMaximumProcessorIndex
+ Returns the maximum processor index value that may be used.
+
+ @param RegisterPeriodicCallback
+ Registers a callback function that will be invoked periodically
+ and asynchronously to the execution of EFI.
+
+ @param RegisterExceptionCallback
+ Registers a callback function that will be called each time the
+ specified processor exception occurs.
+
+ @param InvalidateInstructionCache
+ Invalidate the instruction cache of the processor. This is required
+ by processor architectures where instruction and data caches are
+ not coherent when instructions in the code under debug has been
+ modified by the debug agent.
+**/
+struct _EFI_DEBUG_SUPPORT_PROTOCOL {
+ EFI_INSTRUCTION_SET_ARCHITECTURE Isa;
+ EFI_GET_MAXIMUM_PROCESSOR_INDEX GetMaximumProcessorIndex;
+ EFI_REGISTER_PERIODIC_CALLBACK RegisterPeriodicCallback;
+ EFI_REGISTER_EXCEPTION_CALLBACK RegisterExceptionCallback;
+ EFI_INVALIDATE_INSTRUCTION_CACHE InvalidateInstructionCache;
+};
+
+extern EFI_GUID gEfiDebugSupportProtocolGuid;
+
+#endif
diff --git a/gpxe/src/include/gpxe/efi/Protocol/DevicePath.h b/gpxe/src/include/gpxe/efi/Protocol/DevicePath.h
new file mode 100644
index 00000000..5fb7bf66
--- /dev/null
+++ b/gpxe/src/include/gpxe/efi/Protocol/DevicePath.h
@@ -0,0 +1,560 @@
+/** @file
+ The device path protocol as defined in UEFI 2.0.
+
+ The device path represents a programatic path to a device. It's the view
+ from a software point of view. It also must persist from boot to boot, so
+ it can not contain things like PCI bus numbers that change from boot to boot.
+
+ Copyright (c) 2006 - 2008, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __EFI_DEVICE_PATH_PROTOCOL_H__
+#define __EFI_DEVICE_PATH_PROTOCOL_H__
+
+#include <gpxe/efi/Guid/PcAnsi.h>
+
+///
+/// Device Path protocol
+///
+#define EFI_DEVICE_PATH_PROTOCOL_GUID \
+ { \
+ 0x9576e91, 0x6d3f, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b } \
+ }
+
+//
+// Protocol GUID defined in EFI1.1.
+//
+
+///
+/// Device Path information
+///
+#define DEVICE_PATH_PROTOCOL EFI_DEVICE_PATH_PROTOCOL_GUID
+
+#pragma pack(1)
+
+typedef struct {
+ UINT8 Type;
+ UINT8 SubType;
+ UINT8 Length[2];
+} EFI_DEVICE_PATH_PROTOCOL;
+
+///
+/// For backward-compatible with EFI1.1.
+///
+typedef EFI_DEVICE_PATH_PROTOCOL EFI_DEVICE_PATH;
+
+///
+/// Hardware Device Paths
+///
+#define HARDWARE_DEVICE_PATH 0x01
+
+#define HW_PCI_DP 0x01
+typedef struct {
+ EFI_DEVICE_PATH_PROTOCOL Header;
+ UINT8 Function;
+ UINT8 Device;
+} PCI_DEVICE_PATH;
+
+#define HW_PCCARD_DP 0x02
+typedef struct {
+ EFI_DEVICE_PATH_PROTOCOL Header;
+ UINT8 FunctionNumber;
+} PCCARD_DEVICE_PATH;
+
+#define HW_MEMMAP_DP 0x03
+typedef struct {
+ EFI_DEVICE_PATH_PROTOCOL Header;
+ UINT32 MemoryType;
+ EFI_PHYSICAL_ADDRESS StartingAddress;
+ EFI_PHYSICAL_ADDRESS EndingAddress;
+} MEMMAP_DEVICE_PATH;
+
+#define HW_VENDOR_DP 0x04
+typedef struct {
+ EFI_DEVICE_PATH_PROTOCOL Header;
+ EFI_GUID Guid;
+} VENDOR_DEVICE_PATH;
+
+#define HW_CONTROLLER_DP 0x05
+typedef struct {
+ EFI_DEVICE_PATH_PROTOCOL Header;
+ UINT32 ControllerNumber;
+} CONTROLLER_DEVICE_PATH;
+
+///
+/// ACPI Device Paths
+///
+#define ACPI_DEVICE_PATH 0x02
+
+#define ACPI_DP 0x01
+typedef struct {
+ EFI_DEVICE_PATH_PROTOCOL Header;
+ UINT32 HID;
+ UINT32 UID;
+} ACPI_HID_DEVICE_PATH;
+
+#define ACPI_EXTENDED_DP 0x02
+typedef struct {
+ EFI_DEVICE_PATH_PROTOCOL Header;
+ UINT32 HID;
+ UINT32 UID;
+ UINT32 CID;
+ ///
+ /// Optional variable length _HIDSTR
+ /// Optional variable length _UIDSTR
+ ///
+} ACPI_EXTENDED_HID_DEVICE_PATH;
+
+//
+// EISA ID Macro
+// EISA ID Definition 32-bits
+// bits[15:0] - three character compressed ASCII EISA ID.
+// bits[31:16] - binary number
+// Compressed ASCII is 5 bits per character 0b00001 = 'A' 0b11010 = 'Z'
+//
+#define PNP_EISA_ID_CONST 0x41d0
+#define EISA_ID(_Name, _Num) ((UINT32)((_Name) | (_Num) << 16))
+#define EISA_PNP_ID(_PNPId) (EISA_ID(PNP_EISA_ID_CONST, (_PNPId)))
+#define EFI_PNP_ID(_PNPId) (EISA_ID(PNP_EISA_ID_CONST, (_PNPId)))
+
+#define PNP_EISA_ID_MASK 0xffff
+#define EISA_ID_TO_NUM(_Id) ((_Id) >> 16)
+
+
+#define ACPI_ADR_DP 0x03
+typedef struct {
+ EFI_DEVICE_PATH_PROTOCOL Header;
+ UINT32 ADR;
+} ACPI_ADR_DEVICE_PATH;
+
+#define ACPI_ADR_DISPLAY_TYPE_OTHER 0
+#define ACPI_ADR_DISPLAY_TYPE_VGA 1
+#define ACPI_ADR_DISPLAY_TYPE_TV 2
+#define ACPI_ADR_DISPLAY_TYPE_EXTERNAL_DIGITAL 3
+#define ACPI_ADR_DISPLAY_TYPE_INTERNAL_DIGITAL 4
+
+#define ACPI_DISPLAY_ADR(_DeviceIdScheme, _HeadId, _NonVgaOutput, _BiosCanDetect, _VendorInfo, _Type, _Port, _Index) \
+ ((UINT32)( (((_DeviceIdScheme) & 0x1) << 31) | \
+ (((_HeadId) & 0x7) << 18) | \
+ (((_NonVgaOutput) & 0x1) << 17) | \
+ (((_BiosCanDetect) & 0x1) << 16) | \
+ (((_VendorInfo) & 0xf) << 12) | \
+ (((_Type) & 0xf) << 8) | \
+ (((_Port) & 0xf) << 4) | \
+ ((_Index) & 0xf) ))
+
+///
+/// Messaging Device Paths
+///
+#define MESSAGING_DEVICE_PATH 0x03
+
+#define MSG_ATAPI_DP 0x01
+typedef struct {
+ EFI_DEVICE_PATH_PROTOCOL Header;
+ UINT8 PrimarySecondary;
+ UINT8 SlaveMaster;
+ UINT16 Lun;
+} ATAPI_DEVICE_PATH;
+
+#define MSG_SCSI_DP 0x02
+typedef struct {
+ EFI_DEVICE_PATH_PROTOCOL Header;
+ UINT16 Pun;
+ UINT16 Lun;
+} SCSI_DEVICE_PATH;
+
+#define MSG_FIBRECHANNEL_DP 0x03
+typedef struct {
+ EFI_DEVICE_PATH_PROTOCOL Header;
+ UINT32 Reserved;
+ UINT64 WWN;
+ UINT64 Lun;
+} FIBRECHANNEL_DEVICE_PATH;
+
+#define MSG_1394_DP 0x04
+typedef struct {
+ EFI_DEVICE_PATH_PROTOCOL Header;
+ UINT32 Reserved;
+ UINT64 Guid;
+} F1394_DEVICE_PATH;
+
+#define MSG_USB_DP 0x05
+typedef struct {
+ EFI_DEVICE_PATH_PROTOCOL Header;
+ UINT8 ParentPortNumber;
+ UINT8 InterfaceNumber;
+} USB_DEVICE_PATH;
+
+#define MSG_USB_CLASS_DP 0x0f
+typedef struct {
+ EFI_DEVICE_PATH_PROTOCOL Header;
+ UINT16 VendorId;
+ UINT16 ProductId;
+ UINT8 DeviceClass;
+ UINT8 DeviceSubClass;
+ UINT8 DeviceProtocol;
+} USB_CLASS_DEVICE_PATH;
+
+#define MSG_USB_WWID_DP 0x10
+typedef struct {
+ EFI_DEVICE_PATH_PROTOCOL Header;
+ UINT16 InterfaceNumber;
+ UINT16 VendorId;
+ UINT16 ProductId;
+ // CHAR16 SerialNumber[...];
+} USB_WWID_DEVICE_PATH;
+
+
+#define MSG_DEVICE_LOGICAL_UNIT_DP 0x11
+typedef struct {
+ EFI_DEVICE_PATH_PROTOCOL Header;
+ UINT8 Lun;
+} DEVICE_LOGICAL_UNIT_DEVICE_PATH;
+
+#define MSG_SATA_DP 0x12
+typedef struct {
+ EFI_DEVICE_PATH_PROTOCOL Header;
+ UINT16 HBAPortNumber;
+ UINT16 PortMultiplierPortNumber;
+ UINT16 Lun;
+} SATA_DEVICE_PATH;
+
+#define MSG_I2O_DP 0x06
+typedef struct {
+ EFI_DEVICE_PATH_PROTOCOL Header;
+ UINT32 Tid;
+} I2O_DEVICE_PATH;
+
+#define MSG_MAC_ADDR_DP 0x0b
+typedef struct {
+ EFI_DEVICE_PATH_PROTOCOL Header;
+ EFI_MAC_ADDRESS MacAddress;
+ UINT8 IfType;
+} MAC_ADDR_DEVICE_PATH;
+
+#define MSG_IPv4_DP 0x0c
+typedef struct {
+ EFI_DEVICE_PATH_PROTOCOL Header;
+ EFI_IPv4_ADDRESS LocalIpAddress;
+ EFI_IPv4_ADDRESS RemoteIpAddress;
+ UINT16 LocalPort;
+ UINT16 RemotePort;
+ UINT16 Protocol;
+ BOOLEAN StaticIpAddress;
+} IPv4_DEVICE_PATH;
+
+#define MSG_IPv6_DP 0x0d
+typedef struct {
+ EFI_DEVICE_PATH_PROTOCOL Header;
+ EFI_IPv6_ADDRESS LocalIpAddress;
+ EFI_IPv6_ADDRESS RemoteIpAddress;
+ UINT16 LocalPort;
+ UINT16 RemotePort;
+ UINT16 Protocol;
+ BOOLEAN StaticIpAddress;
+} IPv6_DEVICE_PATH;
+
+#define MSG_INFINIBAND_DP 0x09
+typedef struct {
+ EFI_DEVICE_PATH_PROTOCOL Header;
+ UINT32 ResourceFlags;
+ UINT8 PortGid[16];
+ UINT64 ServiceId;
+ UINT64 TargetPortId;
+ UINT64 DeviceId;
+} INFINIBAND_DEVICE_PATH;
+
+#define INFINIBAND_RESOURCE_FLAG_IOC_SERVICE 0x01
+#define INFINIBAND_RESOURCE_FLAG_EXTENDED_BOOT_ENVIRONMENT 0x02
+#define INFINIBAND_RESOURCE_FLAG_CONSOLE_PROTOCOL 0x04
+#define INFINIBAND_RESOURCE_FLAG_STORAGE_PROTOCOL 0x08
+#define INFINIBAND_RESOURCE_FLAG_NETWORK_PROTOCOL 0x10
+
+#define MSG_UART_DP 0x0e
+typedef struct {
+ EFI_DEVICE_PATH_PROTOCOL Header;
+ UINT32 Reserved;
+ UINT64 BaudRate;
+ UINT8 DataBits;
+ UINT8 Parity;
+ UINT8 StopBits;
+} UART_DEVICE_PATH;
+
+//
+// Use VENDOR_DEVICE_PATH struct
+//
+#define MSG_VENDOR_DP 0x0a
+typedef VENDOR_DEVICE_PATH VENDOR_DEFINED_DEVICE_PATH;
+
+#define DEVICE_PATH_MESSAGING_PC_ANSI EFI_PC_ANSI_GUID
+#define DEVICE_PATH_MESSAGING_VT_100 EFI_VT_100_GUID
+#define DEVICE_PATH_MESSAGING_VT_100_PLUS EFI_VT_100_PLUS_GUID
+#define DEVICE_PATH_MESSAGING_VT_UTF8 EFI_VT_UTF8_GUID
+
+#define DEVICE_PATH_MESSAGING_UART_FLOW_CONTROL EFI_UART_DEVICE_PATH_GUID
+
+typedef struct {
+ EFI_DEVICE_PATH_PROTOCOL Header;
+ EFI_GUID Guid;
+ UINT32 FlowControlMap;
+} UART_FLOW_CONTROL_DEVICE_PATH;
+
+#define DEVICE_PATH_MESSAGING_SAS EFI_SAS_DEVICE_PATH_GUID
+
+typedef struct {
+ EFI_DEVICE_PATH_PROTOCOL Header;
+ EFI_GUID Guid;
+ UINT32 Reserved;
+ UINT64 SasAddress;
+ UINT64 Lun;
+ UINT16 DeviceTopology;
+ UINT16 RelativeTargetPort;
+} SAS_DEVICE_PATH;
+
+#define MSG_ISCSI_DP 0x13
+typedef struct {
+ EFI_DEVICE_PATH_PROTOCOL Header;
+ UINT16 NetworkProtocol;
+ UINT16 LoginOption;
+ UINT64 Lun;
+ UINT16 TargetPortalGroupTag;
+ // CHAR8 iSCSI Target Name
+} ISCSI_DEVICE_PATH;
+
+#define ISCSI_LOGIN_OPTION_NO_HEADER_DIGEST 0x0000
+#define ISCSI_LOGIN_OPTION_HEADER_DIGEST_USING_CRC32C 0x0002
+#define ISCSI_LOGIN_OPTION_NO_DATA_DIGEST 0x0000
+#define ISCSI_LOGIN_OPTION_DATA_DIGEST_USING_CRC32C 0x0008
+#define ISCSI_LOGIN_OPTION_AUTHMETHOD_CHAP 0x0000
+#define ISCSI_LOGIN_OPTION_AUTHMETHOD_NON 0x1000
+#define ISCSI_LOGIN_OPTION_CHAP_BI 0x0000
+#define ISCSI_LOGIN_OPTION_CHAP_UNI 0x2000
+
+//
+// Media Device Path
+//
+#define MEDIA_DEVICE_PATH 0x04
+
+#define MEDIA_HARDDRIVE_DP 0x01
+typedef struct {
+ EFI_DEVICE_PATH_PROTOCOL Header;
+ UINT32 PartitionNumber;
+ UINT64 PartitionStart;
+ UINT64 PartitionSize;
+ UINT8 Signature[16];
+ UINT8 MBRType;
+ UINT8 SignatureType;
+} HARDDRIVE_DEVICE_PATH;
+
+#define MBR_TYPE_PCAT 0x01
+#define MBR_TYPE_EFI_PARTITION_TABLE_HEADER 0x02
+
+#define SIGNATURE_TYPE_MBR 0x01
+#define SIGNATURE_TYPE_GUID 0x02
+
+#define MEDIA_CDROM_DP 0x02
+typedef struct {
+ EFI_DEVICE_PATH_PROTOCOL Header;
+ UINT32 BootEntry;
+ UINT64 PartitionStart;
+ UINT64 PartitionSize;
+} CDROM_DEVICE_PATH;
+
+//
+// Use VENDOR_DEVICE_PATH struct
+//
+#define MEDIA_VENDOR_DP 0x03
+
+#define MEDIA_FILEPATH_DP 0x04
+typedef struct {
+ EFI_DEVICE_PATH_PROTOCOL Header;
+ CHAR16 PathName[1];
+} FILEPATH_DEVICE_PATH;
+
+#define SIZE_OF_FILEPATH_DEVICE_PATH EFI_FIELD_OFFSET(FILEPATH_DEVICE_PATH,PathName)
+
+#define MEDIA_PROTOCOL_DP 0x05
+typedef struct {
+ EFI_DEVICE_PATH_PROTOCOL Header;
+ EFI_GUID Protocol;
+} MEDIA_PROTOCOL_DEVICE_PATH;
+
+
+#define MEDIA_PIWG_FW_VOL_DP 0x7
+typedef struct {
+ EFI_DEVICE_PATH_PROTOCOL Header;
+ EFI_GUID FvName;
+} MEDIA_FW_VOL_DEVICE_PATH;
+
+
+#define MEDIA_PIWG_FW_FILE_DP 0x6
+typedef struct {
+ EFI_DEVICE_PATH_PROTOCOL Header;
+ EFI_GUID FvFileName;
+} MEDIA_FW_VOL_FILEPATH_DEVICE_PATH;
+
+//
+// BBS Device Path
+//
+#define BBS_DEVICE_PATH 0x05
+#define BBS_BBS_DP 0x01
+typedef struct {
+ EFI_DEVICE_PATH_PROTOCOL Header;
+ UINT16 DeviceType;
+ UINT16 StatusFlag;
+ CHAR8 String[1];
+} BBS_BBS_DEVICE_PATH;
+
+//
+// DeviceType definitions - from BBS specification
+//
+#define BBS_TYPE_FLOPPY 0x01
+#define BBS_TYPE_HARDDRIVE 0x02
+#define BBS_TYPE_CDROM 0x03
+#define BBS_TYPE_PCMCIA 0x04
+#define BBS_TYPE_USB 0x05
+#define BBS_TYPE_EMBEDDED_NETWORK 0x06
+#define BBS_TYPE_BEV 0x80
+#define BBS_TYPE_UNKNOWN 0xFF
+
+
+///
+/// Union of all possible Device Paths and pointers to Device Paths
+///
+
+typedef union {
+ EFI_DEVICE_PATH_PROTOCOL DevPath;
+ PCI_DEVICE_PATH Pci;
+ PCCARD_DEVICE_PATH PcCard;
+ MEMMAP_DEVICE_PATH MemMap;
+ VENDOR_DEVICE_PATH Vendor;
+
+ CONTROLLER_DEVICE_PATH Controller;
+ ACPI_HID_DEVICE_PATH Acpi;
+
+ ATAPI_DEVICE_PATH Atapi;
+ SCSI_DEVICE_PATH Scsi;
+ ISCSI_DEVICE_PATH Iscsi;
+ FIBRECHANNEL_DEVICE_PATH FibreChannel;
+
+ F1394_DEVICE_PATH F1394;
+ USB_DEVICE_PATH Usb;
+ SATA_DEVICE_PATH Sata;
+ USB_CLASS_DEVICE_PATH UsbClass;
+ I2O_DEVICE_PATH I2O;
+ MAC_ADDR_DEVICE_PATH MacAddr;
+ IPv4_DEVICE_PATH Ipv4;
+ IPv6_DEVICE_PATH Ipv6;
+ INFINIBAND_DEVICE_PATH InfiniBand;
+ UART_DEVICE_PATH Uart;
+
+ HARDDRIVE_DEVICE_PATH HardDrive;
+ CDROM_DEVICE_PATH CD;
+
+ FILEPATH_DEVICE_PATH FilePath;
+ MEDIA_PROTOCOL_DEVICE_PATH MediaProtocol;
+
+ BBS_BBS_DEVICE_PATH Bbs;
+} EFI_DEV_PATH;
+
+
+
+typedef union {
+ EFI_DEVICE_PATH_PROTOCOL *DevPath;
+ PCI_DEVICE_PATH *Pci;
+ PCCARD_DEVICE_PATH *PcCard;
+ MEMMAP_DEVICE_PATH *MemMap;
+ VENDOR_DEVICE_PATH *Vendor;
+
+ CONTROLLER_DEVICE_PATH *Controller;
+ ACPI_HID_DEVICE_PATH *Acpi;
+ ACPI_EXTENDED_HID_DEVICE_PATH *ExtendedAcpi;
+
+ ATAPI_DEVICE_PATH *Atapi;
+ SCSI_DEVICE_PATH *Scsi;
+ FIBRECHANNEL_DEVICE_PATH *FibreChannel;
+
+ F1394_DEVICE_PATH *F1394;
+ USB_DEVICE_PATH *Usb;
+ SATA_DEVICE_PATH *Sata;
+ USB_CLASS_DEVICE_PATH *UsbClass;
+ I2O_DEVICE_PATH *I2O;
+ MAC_ADDR_DEVICE_PATH *MacAddr;
+ IPv4_DEVICE_PATH *Ipv4;
+ IPv6_DEVICE_PATH *Ipv6;
+ INFINIBAND_DEVICE_PATH *InfiniBand;
+ UART_DEVICE_PATH *Uart;
+
+ HARDDRIVE_DEVICE_PATH *HardDrive;
+ CDROM_DEVICE_PATH *CD;
+
+ FILEPATH_DEVICE_PATH *FilePath;
+ MEDIA_PROTOCOL_DEVICE_PATH *MediaProtocol;
+
+ BBS_BBS_DEVICE_PATH *Bbs;
+ UINT8 *Raw;
+} EFI_DEV_PATH_PTR;
+
+#pragma pack()
+
+#define EFI_DP_TYPE_MASK 0x7F
+#define EFI_DP_TYPE_UNPACKED 0x80
+#define END_DEVICE_PATH_TYPE 0x7f
+
+#define EFI_END_ENTIRE_DEVICE_PATH 0xff
+#define EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE 0xff
+#define EFI_END_INSTANCE_DEVICE_PATH 0x01
+#define END_ENTIRE_DEVICE_PATH_SUBTYPE EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE
+#define END_INSTANCE_DEVICE_PATH_SUBTYPE EFI_END_INSTANCE_DEVICE_PATH
+
+#define EFI_END_DEVICE_PATH_LENGTH (sizeof (EFI_DEVICE_PATH_PROTOCOL))
+#define END_DEVICE_PATH_LENGTH EFI_END_DEVICE_PATH_LENGTH
+
+#define DP_IS_END_TYPE(a)
+#define DP_IS_END_SUBTYPE(a) (((a)->SubType == END_ENTIRE_DEVICE_PATH_SUBTYPE)
+#define DevicePathSubType(a) ((a)->SubType)
+#define IsDevicePathUnpacked(a) ((a)->Type & EFI_DP_TYPE_UNPACKED)
+
+#define EfiDevicePathNodeLength(a) (((a)->Length[0]) | ((a)->Length[1] << 8))
+#define DevicePathNodeLength(a) (EfiDevicePathNodeLength(a))
+#define EfiNextDevicePathNode(a) ((EFI_DEVICE_PATH_PROTOCOL *) (((UINT8 *) (a)) + EfiDevicePathNodeLength (a)))
+#define NextDevicePathNode(a) (EfiNextDevicePathNode(a))
+
+#define EfiDevicePathType(a) (((a)->Type) & EFI_DP_TYPE_MASK)
+#define DevicePathType(a) (EfiDevicePathType(a))
+#define EfiIsDevicePathEndType(a) (EfiDevicePathType (a) == END_DEVICE_PATH_TYPE)
+#define IsDevicePathEndType(a) (EfiIsDevicePathEndType(a))
+
+
+#define EfiIsDevicePathEndSubType(a) ((a)->SubType == EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE)
+#define IsDevicePathEndSubType(a) (EfiIsDevicePathEndSubType(a))
+#define EfiIsDevicePathEndInstanceSubType(a) ((a)->SubType == EFI_END_INSTANCE_DEVICE_PATH)
+
+#define EfiIsDevicePathEnd(a) (EfiIsDevicePathEndType (a) && EfiIsDevicePathEndSubType (a))
+#define IsDevicePathEnd(a) (EfiIsDevicePathEnd(a))
+#define EfiIsDevicePathEndInstance(a) (EfiIsDevicePathEndType (a) && EfiIsDevicePathEndInstanceSubType (a))
+
+
+#define SetDevicePathNodeLength(a,l) { \
+ (a)->Length[0] = (UINT8) (l); \
+ (a)->Length[1] = (UINT8) ((l) >> 8); \
+ }
+
+#define SetDevicePathEndNode(a) { \
+ (a)->Type = END_DEVICE_PATH_TYPE; \
+ (a)->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE; \
+ (a)->Length[0] = sizeof(EFI_DEVICE_PATH_PROTOCOL); \
+ (a)->Length[1] = 0; \
+ }
+
+extern EFI_GUID gEfiDevicePathProtocolGuid;
+
+#endif
diff --git a/gpxe/src/include/gpxe/efi/Protocol/DriverBinding.h b/gpxe/src/include/gpxe/efi/Protocol/DriverBinding.h
new file mode 100644
index 00000000..9072a288
--- /dev/null
+++ b/gpxe/src/include/gpxe/efi/Protocol/DriverBinding.h
@@ -0,0 +1,166 @@
+/** @file
+ UEFI DriverBinding Protocol is defined in UEFI specification.
+
+ This protocol is produced by every driver that follows the UEFI Driver Model,
+ and it is the central component that allows drivers and controllers to be managed.
+
+ Copyright (c) 2006 - 2008, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __EFI_DRIVER_BINDING_H__
+#define __EFI_DRIVER_BINDING_H__
+
+#include <gpxe/efi/PiDxe.h>
+#include <gpxe/efi/Protocol/DevicePath.h>
+///
+/// Global ID for the ControllerHandle Driver Protocol
+///
+#define EFI_DRIVER_BINDING_PROTOCOL_GUID \
+ { \
+ 0x18a031ab, 0xb443, 0x4d1a, {0xa5, 0xc0, 0xc, 0x9, 0x26, 0x1e, 0x9f, 0x71 } \
+ }
+
+typedef struct _EFI_DRIVER_BINDING_PROTOCOL EFI_DRIVER_BINDING_PROTOCOL;
+
+/**
+ Test to see if this driver supports ControllerHandle.
+
+ @param This Protocol instance pointer.
+ @param ControllerHandle Handle of device to test
+ @param RemainingDevicePath Optional parameter use to pick a specific child
+ device to start.
+
+ @retval EFI_SUCCESS This driver supports this device
+ @retval EFI_ALREADY_STARTED This driver is already running on this device
+ @retval other This driver does not support this device
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_DRIVER_BINDING_SUPPORTED)(
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
+ );
+
+/**
+ Start this driver on ControllerHandle.
+
+ @param This Protocol instance pointer.
+ @param ControllerHandle Handle of device to bind driver to
+ @param RemainingDevicePath Optional parameter use to pick a specific child
+ device to start.
+
+ @retval EFI_SUCCESS This driver is added to ControllerHandle
+ @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
+ @retval other This driver does not support this device
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_DRIVER_BINDING_START)(
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
+ );
+
+/**
+ Stop this driver on ControllerHandle.
+
+ @param This Protocol instance pointer.
+ @param ControllerHandle Handle of device to stop driver on
+ @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
+ children is zero stop the entire bus driver.
+ @param ChildHandleBuffer List of Child Handles to Stop.
+
+ @retval EFI_SUCCESS This driver is removed ControllerHandle
+ @retval other This driver was not removed from this device
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_DRIVER_BINDING_STOP)(
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer OPTIONAL
+ );
+
+//
+// Interface structure for the ControllerHandle Driver Protocol
+//
+/**
+ @par Protocol Description:
+ This protocol provides the services required to determine if a driver supports a given controller.
+ If a controller is supported, then it also provides routines to start and stop the controller.
+
+ @param Supported
+ Tests to see if this driver supports a given controller. This service
+ is called by the EFI boot service ConnectController(). In
+ order to make drivers as small as possible, there are a few calling
+ restrictions for this service. ConnectController() must
+ follow these calling restrictions. If any other agent wishes to call
+ Supported() it must also follow these calling restrictions.
+
+
+ @param Start
+ Starts a controller using this driver. This service is called by the
+ EFI boot service ConnectController(). In order to make
+ drivers as small as possible, there are a few calling restrictions for
+ this service. ConnectController() must follow these
+ calling restrictions. If any other agent wishes to call Start() it
+ must also follow these calling restrictions.
+
+ @param Stop
+ Stops a controller using this driver. This service is called by the
+ EFI boot service DisconnectController(). In order to
+ make drivers as small as possible, there are a few calling
+ restrictions for this service. DisconnectController()
+ must follow these calling restrictions. If any other agent wishes
+ to call Stop() it must also follow these calling restrictions.
+
+ @param Version
+ The version number of the UEFI driver that produced the
+ EFI_DRIVER_BINDING_PROTOCOL. This field is used by
+ the EFI boot service ConnectController() to determine
+ the order that driver's Supported() service will be used when
+ a controller needs to be started. EFI Driver Binding Protocol
+ instances with higher Version values will be used before ones
+ with lower Version values. The Version values of 0x0-
+ 0x0f and 0xfffffff0-0xffffffff are reserved for
+ platform/OEM specific drivers. The Version values of 0x10-
+ 0xffffffef are reserved for IHV-developed drivers.
+
+ @param ImageHandle
+ The image handle of the UEFI driver that produced this instance
+ of the EFI_DRIVER_BINDING_PROTOCOL.
+
+ @param DriverBindingHandle
+ The handle on which this instance of the
+ EFI_DRIVER_BINDING_PROTOCOL is installed. In most
+ cases, this is the same handle as ImageHandle. However, for
+ UEFI drivers that produce more than one instance of the
+ EFI_DRIVER_BINDING_PROTOCOL, this value may not be
+ the same as ImageHandle.
+
+**/
+struct _EFI_DRIVER_BINDING_PROTOCOL {
+ EFI_DRIVER_BINDING_SUPPORTED Supported;
+ EFI_DRIVER_BINDING_START Start;
+ EFI_DRIVER_BINDING_STOP Stop;
+ UINT32 Version;
+ EFI_HANDLE ImageHandle;
+ EFI_HANDLE DriverBindingHandle;
+};
+
+extern EFI_GUID gEfiDriverBindingProtocolGuid;
+
+#endif
diff --git a/gpxe/src/include/gpxe/efi/Protocol/PciIo.h b/gpxe/src/include/gpxe/efi/Protocol/PciIo.h
new file mode 100644
index 00000000..5a241ffc
--- /dev/null
+++ b/gpxe/src/include/gpxe/efi/Protocol/PciIo.h
@@ -0,0 +1,577 @@
+/** @file
+ EFI PCI I/O Protocol provides the basic Memory, I/O, PCI configuration,
+ and DMA interfaces that a driver uses to access its PCI controller.
+
+ Copyright (c) 2006 - 2008, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __PCI_IO_H__
+#define __PCI_IO_H__
+
+///
+/// Global ID for the PCI I/O Protocol
+///
+#define EFI_PCI_IO_PROTOCOL_GUID \
+ { \
+ 0x4cf5b200, 0x68b8, 0x4ca5, {0x9e, 0xec, 0xb2, 0x3e, 0x3f, 0x50, 0x2, 0x9a } \
+ }
+
+typedef struct _EFI_PCI_IO_PROTOCOL EFI_PCI_IO_PROTOCOL;
+
+///
+/// Prototypes for the PCI I/O Protocol
+///
+typedef enum {
+ EfiPciIoWidthUint8 = 0,
+ EfiPciIoWidthUint16,
+ EfiPciIoWidthUint32,
+ EfiPciIoWidthUint64,
+ EfiPciIoWidthFifoUint8,
+ EfiPciIoWidthFifoUint16,
+ EfiPciIoWidthFifoUint32,
+ EfiPciIoWidthFifoUint64,
+ EfiPciIoWidthFillUint8,
+ EfiPciIoWidthFillUint16,
+ EfiPciIoWidthFillUint32,
+ EfiPciIoWidthFillUint64,
+ EfiPciIoWidthMaximum
+} EFI_PCI_IO_PROTOCOL_WIDTH;
+
+//
+// Complete PCI address generater
+//
+#define EFI_PCI_IO_PASS_THROUGH_BAR 0xff // Special BAR that passes a memory or I/O cycle through unchanged
+#define EFI_PCI_IO_ATTRIBUTE_MASK 0x077f // All the following I/O and Memory cycles
+#define EFI_PCI_IO_ATTRIBUTE_ISA_MOTHERBOARD_IO 0x0001 // I/O cycles 0x0000-0x00FF (10 bit decode)
+#define EFI_PCI_IO_ATTRIBUTE_ISA_IO 0x0002 // I/O cycles 0x0100-0x03FF or greater (10 bit decode)
+#define EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO 0x0004 // I/O cycles 0x3C6, 0x3C8, 0x3C9 (10 bit decode)
+#define EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY 0x0008 // MEM cycles 0xA0000-0xBFFFF (24 bit decode)
+#define EFI_PCI_IO_ATTRIBUTE_VGA_IO 0x0010 // I/O cycles 0x3B0-0x3BB and 0x3C0-0x3DF (10 bit decode)
+#define EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO 0x0020 // I/O cycles 0x1F0-0x1F7, 0x3F6, 0x3F7 (10 bit decode)
+#define EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO 0x0040 // I/O cycles 0x170-0x177, 0x376, 0x377 (10 bit decode)
+#define EFI_PCI_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE 0x0080 // Map a memory range so write are combined
+#define EFI_PCI_IO_ATTRIBUTE_IO 0x0100 // Enable the I/O decode bit in the PCI Config Header
+#define EFI_PCI_IO_ATTRIBUTE_MEMORY 0x0200 // Enable the Memory decode bit in the PCI Config Header
+#define EFI_PCI_IO_ATTRIBUTE_BUS_MASTER 0x0400 // Enable the DMA bit in the PCI Config Header
+#define EFI_PCI_IO_ATTRIBUTE_MEMORY_CACHED 0x0800 // Map a memory range so all r/w accesses are cached
+#define EFI_PCI_IO_ATTRIBUTE_MEMORY_DISABLE 0x1000 // Disable a memory range
+#define EFI_PCI_IO_ATTRIBUTE_EMBEDDED_DEVICE 0x2000 // Clear for an add-in PCI Device
+#define EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM 0x4000 // Clear for a physical PCI Option ROM accessed through ROM BAR
+#define EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE 0x8000 // Clear for PCI controllers that can not genrate a DAC
+#define EFI_PCI_IO_ATTRIBUTE_ISA_IO_16 0x10000 // I/O cycles 0x0100-0x03FF or greater (16 bit decode)
+#define EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16 0x20000 // I/O cycles 0x3C6, 0x3C8, 0x3C9 (16 bit decode)
+#define EFI_PCI_IO_ATTRIBUTE_VGA_IO_16 0x30000 // I/O cycles 0x3B0-0x3BB and 0x3C0-0x3DF (16 bit decode)
+
+#define EFI_PCI_DEVICE_ENABLE (EFI_PCI_IO_ATTRIBUTE_IO | EFI_PCI_IO_ATTRIBUTE_MEMORY | EFI_PCI_IO_ATTRIBUTE_BUS_MASTER)
+#define EFI_VGA_DEVICE_ENABLE (EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO | EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY | EFI_PCI_IO_ATTRIBUTE_VGA_IO | EFI_PCI_IO_ATTRIBUTE_IO)
+
+///
+/// *******************************************************
+/// EFI_PCI_IO_PROTOCOL_OPERATION
+/// *******************************************************
+///
+typedef enum {
+ EfiPciIoOperationBusMasterRead,
+ EfiPciIoOperationBusMasterWrite,
+ EfiPciIoOperationBusMasterCommonBuffer,
+ EfiPciIoOperationMaximum
+} EFI_PCI_IO_PROTOCOL_OPERATION;
+
+///
+/// *******************************************************
+/// EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION
+/// *******************************************************
+///
+typedef enum {
+ EfiPciIoAttributeOperationGet,
+ EfiPciIoAttributeOperationSet,
+ EfiPciIoAttributeOperationEnable,
+ EfiPciIoAttributeOperationDisable,
+ EfiPciIoAttributeOperationSupported,
+ EfiPciIoAttributeOperationMaximum
+} EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION;
+
+/**
+ Reads from the memory space of a PCI controller. Returns when either the polling exit criteria is
+ satisfied or after a defined duration.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Width Signifies the width of the memory or I/O operations.
+ @param BarIndex The BAR index of the standard PCI Configuration header to use as the
+ base address for the memory operation to perform.
+ @param Offset The offset within the selected BAR to start the memory operation.
+ @param Mask Mask used for the polling criteria.
+ @param Value The comparison value used for the polling exit criteria.
+ @param Delay The number of 100 ns units to poll.
+ @param Result Pointer to the last value read from the memory location.
+
+ @retval EFI_SUCCESS The last data returned from the access matched the poll exit criteria.
+ @retval EFI_UNSUPPORTED BarIndex not valid for this PCI controller.
+ @retval EFI_UNSUPPORTED Offset is not valid for the BarIndex of this PCI controller.
+ @retval EFI_TIMEOUT Delay expired before a match occurred.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_IO_PROTOCOL_POLL_IO_MEM)(
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
+ IN UINT8 BarIndex,
+ IN UINT64 Offset,
+ IN UINT64 Mask,
+ IN UINT64 Value,
+ IN UINT64 Delay,
+ OUT UINT64 *Result
+ );
+
+/**
+ Enable a PCI driver to access PCI controller registers in the PCI memory or I/O space.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Width Signifies the width of the memory or I/O operations.
+ @param BarIndex The BAR index of the standard PCI Configuration header to use as the
+ base address for the memory or I/O operation to perform.
+ @param Offset The offset within the selected BAR to start the memory or I/O operation.
+ @param Count The number of memory or I/O operations to perform.
+ @param Buffer For read operations, the destination buffer to store the results. For write
+ operations, the source buffer to write data from.
+
+ @retval EFI_SUCCESS The data was read from or written to the PCI controller.
+ @retval EFI_UNSUPPORTED BarIndex not valid for this PCI controller.
+ @retval EFI_UNSUPPORTED The address range specified by Offset, Width, and Count is not
+ valid for the PCI BAR specified by BarIndex.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_IO_PROTOCOL_IO_MEM)(
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
+ IN UINT8 BarIndex,
+ IN UINT64 Offset,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ );
+
+typedef struct {
+ EFI_PCI_IO_PROTOCOL_IO_MEM Read;
+ EFI_PCI_IO_PROTOCOL_IO_MEM Write;
+} EFI_PCI_IO_PROTOCOL_ACCESS;
+
+/**
+ Enable a PCI driver to access PCI controller registers in PCI configuration space.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Width Signifies the width of the memory operations.
+ @param Offset The offset within the PCI configuration space for the PCI controller.
+ @param Count The number of PCI configuration operations to perform.
+ @param Buffer For read operations, the destination buffer to store the results. For write
+ operations, the source buffer to write data from.
+
+
+ @retval EFI_SUCCESS The data was read from or written to the PCI controller.
+ @retval EFI_UNSUPPORTED The address range specified by Offset, Width, and Count is not
+ valid for the PCI configuration header of the PCI controller.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_INVALID_PARAMETER Buffer is NULL or Width is invalid.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_IO_PROTOCOL_CONFIG)(
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
+ IN UINT32 Offset,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ );
+
+typedef struct {
+ EFI_PCI_IO_PROTOCOL_CONFIG Read;
+ EFI_PCI_IO_PROTOCOL_CONFIG Write;
+} EFI_PCI_IO_PROTOCOL_CONFIG_ACCESS;
+
+/**
+ Enables a PCI driver to copy one region of PCI memory space to another region of PCI
+ memory space.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Width Signifies the width of the memory operations.
+ @param DestBarIndex The BAR index in the standard PCI Configuration header to use as the
+ base address for the memory operation to perform.
+ @param DestOffset The destination offset within the BAR specified by DestBarIndex to
+ start the memory writes for the copy operation.
+ @param SrcBarIndex The BAR index in the standard PCI Configuration header to use as the
+ base address for the memory operation to perform.
+ @param SrcOffset The source offset within the BAR specified by SrcBarIndex to start
+ the memory reads for the copy operation.
+ @param Count The number of memory operations to perform. Bytes moved is Width
+ size * Count, starting at DestOffset and SrcOffset.
+
+ @retval EFI_SUCCESS The data was copied from one memory region to another memory region.
+ @retval EFI_UNSUPPORTED DestBarIndex not valid for this PCI controller.
+ @retval EFI_UNSUPPORTED SrcBarIndex not valid for this PCI controller.
+ @retval EFI_UNSUPPORTED The address range specified by DestOffset, Width, and Count
+ is not valid for the PCI BAR specified by DestBarIndex.
+ @retval EFI_UNSUPPORTED The address range specified by SrcOffset, Width, and Count is
+ not valid for the PCI BAR specified by SrcBarIndex.
+ @retval EFI_INVALID_PARAMETER Width is invalid.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_IO_PROTOCOL_COPY_MEM)(
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
+ IN UINT8 DestBarIndex,
+ IN UINT64 DestOffset,
+ IN UINT8 SrcBarIndex,
+ IN UINT64 SrcOffset,
+ IN UINTN Count
+ );
+
+/**
+ Provides the PCI controller-Cspecific addresses needed to access system memory.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Operation Indicates if the bus master is going to read or write to system memory.
+ @param HostAddress The system memory address to map to the PCI controller.
+ @param NumberOfBytes On input the number of bytes to map. On output the number of bytes
+ that were mapped.
+ @param DeviceAddress The resulting map address for the bus master PCI controller to use to
+ access the hosts HostAddress.
+ @param Mapping A resulting value to pass to Unmap().
+
+ @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes.
+ @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common buffer.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_DEVICE_ERROR The system hardware could not map the requested address.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_IO_PROTOCOL_MAP)(
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN EFI_PCI_IO_PROTOCOL_OPERATION Operation,
+ IN VOID *HostAddress,
+ IN OUT UINTN *NumberOfBytes,
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
+ OUT VOID **Mapping
+ );
+
+/**
+ Completes the Map() operation and releases any corresponding resources.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Mapping The mapping value returned from Map().
+
+ @retval EFI_SUCCESS The range was unmapped.
+ @retval EFI_DEVICE_ERROR The data was not committed to the target system memory.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_IO_PROTOCOL_UNMAP)(
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN VOID *Mapping
+ );
+
+/**
+ Allocates pages that are suitable for an EfiPciIoOperationBusMasterCommonBuffer
+ mapping.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Type This parameter is not used and must be ignored.
+ @param MemoryType The type of memory to allocate, EfiBootServicesData or
+ EfiRuntimeServicesData.
+ @param Pages The number of pages to allocate.
+ @param HostAddress A pointer to store the base system memory address of the
+ allocated range.
+ @param Attributes The requested bit mask of attributes for the allocated range.
+
+ @retval EFI_SUCCESS The requested memory pages were allocated.
+ @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are
+ MEMORY_WRITE_COMBINE and MEMORY_CACHED.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_IO_PROTOCOL_ALLOCATE_BUFFER)(
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN EFI_ALLOCATE_TYPE Type,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN Pages,
+ OUT VOID **HostAddress,
+ IN UINT64 Attributes
+ );
+
+/**
+ Frees memory that was allocated with AllocateBuffer().
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Pages The number of pages to free.
+ @param HostAddress The base system memory address of the allocated range.
+
+ @retval EFI_SUCCESS The requested memory pages were freed.
+ @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages
+ was not allocated with AllocateBuffer().
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_IO_PROTOCOL_FREE_BUFFER)(
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN UINTN Pages,
+ IN VOID *HostAddress
+ );
+
+/**
+ Flushes all PCI posted write transactions from a PCI host bridge to system memory.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+
+ @retval EFI_SUCCESS The PCI posted write transactions were flushed from the PCI host
+ bridge to system memory.
+ @retval EFI_DEVICE_ERROR The PCI posted write transactions were not flushed from the PCI
+ host bridge due to a hardware error.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_IO_PROTOCOL_FLUSH)(
+ IN EFI_PCI_IO_PROTOCOL *This
+ );
+
+/**
+ Retrieves this PCI controller's current PCI bus number, device number, and function number.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param SegmentNumber The PCI controller's current PCI segment number.
+ @param BusNumber The PCI controller's current PCI bus number.
+ @param DeviceNumber The PCI controller's current PCI device number.
+ @param FunctionNumber The PCI controller's current PCI function number.
+
+ @retval EFI_SUCCESS The PCI controller location was returned.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_IO_PROTOCOL_GET_LOCATION)(
+ IN EFI_PCI_IO_PROTOCOL *This,
+ OUT UINTN *SegmentNumber,
+ OUT UINTN *BusNumber,
+ OUT UINTN *DeviceNumber,
+ OUT UINTN *FunctionNumber
+ );
+
+/**
+ Performs an operation on the attributes that this PCI controller supports. The operations include
+ getting the set of supported attributes, retrieving the current attributes, setting the current
+ attributes, enabling attributes, and disabling attributes.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Operation The operation to perform on the attributes for this PCI controller.
+ @param Attributes The mask of attributes that are used for Set, Enable, and Disable
+ operations.
+ @param Result A pointer to the result mask of attributes that are returned for the Get
+ and Supported operations.
+
+ @retval EFI_SUCCESS The operation on the PCI controller's attributes was completed.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_UNSUPPORTED one or more of the bits set in
+ Attributes are not supported by this PCI controller or one of
+ its parent bridges when Operation is Set, Enable or Disable.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_IO_PROTOCOL_ATTRIBUTES)(
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION Operation,
+ IN UINT64 Attributes,
+ OUT UINT64 *Result OPTIONAL
+ );
+
+/**
+ Gets the attributes that this PCI controller supports setting on a BAR using
+ SetBarAttributes(), and retrieves the list of resource descriptors for a BAR.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param BarIndex The BAR index of the standard PCI Configuration header to use as the
+ base address for resource range. The legal range for this field is 0..5.
+ @param Supports A pointer to the mask of attributes that this PCI controller supports
+ setting for this BAR with SetBarAttributes().
+ @param Resources A pointer to the ACPI 2.0 resource descriptors that describe the current
+ configuration of this BAR of the PCI controller.
+
+ @retval EFI_SUCCESS If Supports is not NULL, then the attributes that the PCI
+ controller supports are returned in Supports. If Resources
+ is not NULL, then the ACPI 2.0 resource descriptors that the PCI
+ controller is currently using are returned in Resources.
+ @retval EFI_INVALID_PARAMETER Both Supports and Attributes are NULL.
+ @retval EFI_UNSUPPORTED BarIndex not valid for this PCI controller.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources available to allocate
+ Resources.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_IO_PROTOCOL_GET_BAR_ATTRIBUTES)(
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN UINT8 BarIndex,
+ OUT UINT64 *Supports, OPTIONAL
+ OUT VOID **Resources OPTIONAL
+ );
+
+/**
+ Sets the attributes for a range of a BAR on a PCI controller.
+
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+ @param Attributes The mask of attributes to set for the resource range specified by
+ BarIndex, Offset, and Length.
+ @param BarIndex The BAR index of the standard PCI Configuration header to use as the
+ base address for resource range. The legal range for this field is 0..5.
+ @param Offset A pointer to the BAR relative base address of the resource range to be
+ modified by the attributes specified by Attributes.
+ @param Length A pointer to the length of the resource range to be modified by the
+ attributes specified by Attributes.
+
+ @retval EFI_SUCCESS The set of attributes specified by Attributes for the resource
+ range specified by BarIndex, Offset, and Length were
+ set on the PCI controller, and the actual resource range is returned
+ in Offset and Length.
+ @retval EFI_INVALID_PARAMETER Offset or Length is NULL.
+ @retval EFI_UNSUPPORTED BarIndex not valid for this PCI controller.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources to set the attributes on the
+ resource range specified by BarIndex, Offset, and
+ Length.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_IO_PROTOCOL_SET_BAR_ATTRIBUTES)(
+ IN EFI_PCI_IO_PROTOCOL *This,
+ IN UINT64 Attributes,
+ IN UINT8 BarIndex,
+ IN OUT UINT64 *Offset,
+ IN OUT UINT64 *Length
+ );
+
+/**
+ @par Protocol Description:
+ The EFI_PCI_IO_PROTOCOL provides the basic Memory, I/O, PCI configuration,
+ and DMA interfaces that are used to abstract accesses to PCI controllers.
+ There is one EFI_PCI_IO_PROTOCOL instance for each PCI controller on a PCI bus.
+ A device driver that wishes to manage a PCI controller in a system will have to
+ retrieve the EFI_PCI_IO_PROTOCOL instance that is associated with the PCI controller.
+
+ @param PollMem
+ Polls an address in PCI memory space until an exit condition is met, or a timeout occurs.
+
+ @param PollIo
+ Polls an address in PCI I/O space until an exit condition is met, or a timeout occurs.
+
+ @param Mem.Read
+ Allows BAR relative reads to PCI memory space.
+
+ @param Mem.Write
+ Allows BAR relative writes to PCI memory space.
+
+ @param Io.Read
+ Allows BAR relative reads to PCI I/O space.
+
+ @param Io.Write
+ Allows BAR relative writes to PCI I/O space.
+
+ @param Pci.Read
+ Allows PCI controller relative reads to PCI configuration space.
+
+ @param Pci.Write
+ Allows PCI controller relative writes to PCI configuration space.
+
+ @param CopyMem
+ Allows one region of PCI memory space to be copied to another region of PCI memory space.
+
+ @param Map
+ Provides the PCI controller's specific address needed to access system memory for DMA.
+
+ @param Unmap
+ Releases any resources allocated by Map().
+
+ @param AllocateBuffer
+ Allocates pages that are suitable for a common buffer mapping.
+
+ @param FreeBuffer
+ Frees pages that were allocated with AllocateBuffer().
+
+ @param Flush
+ Flushes all PCI posted write transactions to system memory.
+
+ @param GetLocation
+ Retrieves this PCI controller's current PCI bus number, device number, and function number.
+
+ @param Attributes
+ Performs an operation on the attributes that this PCI controller supports.
+ The operations include getting the set of supported attributes, retrieving
+ the current attributes, setting the current
+ attributes, enabling attributes, and disabling attributes.
+
+ @param GetBarAttributes
+ Gets the attributes that this PCI controller supports setting on a BAR using
+ SetBarAttributes(), and retrieves the list of resource descriptors for a BAR.
+
+ @param SetBarAttributes
+ Sets the attributes for a range of a BAR on a PCI controller.
+
+ @param RomSize
+ The size, in bytes, of the ROM image.
+
+ @param RomImage
+ A pointer to the in memory copy of the ROM image. The PCI Bus Driver is responsible
+ for allocating memory for the ROM image, and copying the contents of the ROM to memory.
+ The contents of this buffer are either from the PCI option ROM that can be accessed
+ through the ROM BAR of the PCI controller, or it is from a platform-specific location.
+ The Attributes() function can be used to determine from which of these two sources
+ the RomImage buffer was initialized.
+
+**/
+struct _EFI_PCI_IO_PROTOCOL {
+ EFI_PCI_IO_PROTOCOL_POLL_IO_MEM PollMem;
+ EFI_PCI_IO_PROTOCOL_POLL_IO_MEM PollIo;
+ EFI_PCI_IO_PROTOCOL_ACCESS Mem;
+ EFI_PCI_IO_PROTOCOL_ACCESS Io;
+ EFI_PCI_IO_PROTOCOL_CONFIG_ACCESS Pci;
+ EFI_PCI_IO_PROTOCOL_COPY_MEM CopyMem;
+ EFI_PCI_IO_PROTOCOL_MAP Map;
+ EFI_PCI_IO_PROTOCOL_UNMAP Unmap;
+ EFI_PCI_IO_PROTOCOL_ALLOCATE_BUFFER AllocateBuffer;
+ EFI_PCI_IO_PROTOCOL_FREE_BUFFER FreeBuffer;
+ EFI_PCI_IO_PROTOCOL_FLUSH Flush;
+ EFI_PCI_IO_PROTOCOL_GET_LOCATION GetLocation;
+ EFI_PCI_IO_PROTOCOL_ATTRIBUTES Attributes;
+ EFI_PCI_IO_PROTOCOL_GET_BAR_ATTRIBUTES GetBarAttributes;
+ EFI_PCI_IO_PROTOCOL_SET_BAR_ATTRIBUTES SetBarAttributes;
+ UINT64 RomSize;
+ VOID *RomImage;
+};
+
+extern EFI_GUID gEfiPciIoProtocolGuid;
+
+#endif
diff --git a/gpxe/src/include/gpxe/efi/Protocol/PciRootBridgeIo.h b/gpxe/src/include/gpxe/efi/Protocol/PciRootBridgeIo.h
new file mode 100644
index 00000000..c15c72f7
--- /dev/null
+++ b/gpxe/src/include/gpxe/efi/Protocol/PciRootBridgeIo.h
@@ -0,0 +1,450 @@
+/** @file
+ PCI Root Bridge I/O protocol as defined in the UEFI 2.0 specification.
+
+ PCI Root Bridge I/O protocol is used by PCI Bus Driver to perform PCI Memory, PCI I/O,
+ and PCI Configuration cycles on a PCI Root Bridge. It also provides services to perform
+ defferent types of bus mastering DMA
+
+ Copyright (c) 2006 - 2008, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __PCI_ROOT_BRIDGE_IO_H__
+#define __PCI_ROOT_BRIDGE_IO_H__
+
+#include <gpxe/efi/PiDxe.h>
+
+#define EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_GUID \
+ { \
+ 0x2f707ebb, 0x4a1a, 0x11d4, {0x9a, 0x38, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d } \
+ }
+
+typedef struct _EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL;
+
+typedef enum {
+ EfiPciWidthUint8,
+ EfiPciWidthUint16,
+ EfiPciWidthUint32,
+ EfiPciWidthUint64,
+ EfiPciWidthFifoUint8,
+ EfiPciWidthFifoUint16,
+ EfiPciWidthFifoUint32,
+ EfiPciWidthFifoUint64,
+ EfiPciWidthFillUint8,
+ EfiPciWidthFillUint16,
+ EfiPciWidthFillUint32,
+ EfiPciWidthFillUint64,
+ EfiPciWidthMaximum
+} EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH;
+
+typedef enum {
+ EfiPciOperationBusMasterRead,
+ EfiPciOperationBusMasterWrite,
+ EfiPciOperationBusMasterCommonBuffer,
+ EfiPciOperationBusMasterRead64,
+ EfiPciOperationBusMasterWrite64,
+ EfiPciOperationBusMasterCommonBuffer64,
+ EfiPciOperationMaximum
+} EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION;
+
+#define EFI_PCI_ATTRIBUTE_ISA_MOTHERBOARD_IO 0x0001
+#define EFI_PCI_ATTRIBUTE_ISA_IO 0x0002
+#define EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO 0x0004
+#define EFI_PCI_ATTRIBUTE_VGA_MEMORY 0x0008
+#define EFI_PCI_ATTRIBUTE_VGA_IO 0x0010
+#define EFI_PCI_ATTRIBUTE_IDE_PRIMARY_IO 0x0020
+#define EFI_PCI_ATTRIBUTE_IDE_SECONDARY_IO 0x0040
+#define EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE 0x0080
+#define EFI_PCI_ATTRIBUTE_MEMORY_CACHED 0x0800
+#define EFI_PCI_ATTRIBUTE_MEMORY_DISABLE 0x1000
+#define EFI_PCI_ATTRIBUTE_DUAL_ADDRESS_CYCLE 0x8000
+
+#define EFI_PCI_ATTRIBUTE_VALID_FOR_ALLOCATE_BUFFER (EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE | EFI_PCI_ATTRIBUTE_MEMORY_CACHED | EFI_PCI_ATTRIBUTE_DUAL_ADDRESS_CYCLE)
+
+#define EFI_PCI_ATTRIBUTE_INVALID_FOR_ALLOCATE_BUFFER (~EFI_PCI_ATTRIBUTE_VALID_FOR_ALLOCATE_BUFFER)
+
+#define EFI_PCI_ADDRESS(bus, dev, func, reg) \
+ ((UINT64) ((((UINTN) bus) << 24) + (((UINTN) dev) << 16) + (((UINTN) func) << 8) + ((UINTN) reg)))
+
+typedef struct {
+ UINT8 Register;
+ UINT8 Function;
+ UINT8 Device;
+ UINT8 Bus;
+ UINT32 ExtendedRegister;
+} EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS;
+
+/**
+ Reads from the I/O space of a PCI Root Bridge. Returns when either the polling exit criteria is
+ satisfied or after a defined duration.
+
+ @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+ @param Width Signifies the width of the memory or I/O operations.
+ @param Address The base address of the memory or I/O operations.
+ @param Mask Mask used for the polling criteria.
+ @param Value The comparison value used for the polling exit criteria.
+ @param Delay The number of 100 ns units to poll.
+ @param Result Pointer to the last value read from the memory location.
+
+ @retval EFI_SUCCESS The last data returned from the access matched the poll exit criteria.
+ @retval EFI_TIMEOUT Delay expired before a match occurred.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_POLL_IO_MEM)(
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 Address,
+ IN UINT64 Mask,
+ IN UINT64 Value,
+ IN UINT64 Delay,
+ OUT UINT64 *Result
+ );
+
+/**
+ Enables a PCI driver to access PCI controller registers in the PCI root bridge memory space.
+
+ @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+ @param Width Signifies the width of the memory operations.
+ @param Address The base address of the memory operations.
+ @param Count The number of memory operations to perform.
+ @param Buffer For read operations, the destination buffer to store the results. For write
+ operations, the source buffer to write data from.
+
+ @retval EFI_SUCCESS The data was read from or written to the PCI root bridge.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_IO_MEM)(
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ );
+
+typedef struct {
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_IO_MEM Read;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_IO_MEM Write;
+} EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_ACCESS;
+
+/**
+ Enables a PCI driver to copy one region of PCI root bridge memory space to another region of PCI
+ root bridge memory space.
+
+ @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL instance.
+ @param Width Signifies the width of the memory operations.
+ @param DestAddress The destination address of the memory operation.
+ @param SrcAddress The source address of the memory operation.
+ @param Count The number of memory operations to perform.
+
+ @retval EFI_SUCCESS The data was copied from one memory region to another memory region.
+ @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_COPY_MEM)(
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 DestAddress,
+ IN UINT64 SrcAddress,
+ IN UINTN Count
+ );
+
+/**
+ Provides the PCI controller-Cspecific addresses required to access system memory from a
+ DMA bus master.
+
+ @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+ @param Operation Indicates if the bus master is going to read or write to system memory.
+ @param HostAddress The system memory address to map to the PCI controller.
+ @param NumberOfBytes On input the number of bytes to map. On output the number of bytes
+ that were mapped.
+ @param DeviceAddress The resulting map address for the bus master PCI controller to use to
+ access the hosts HostAddress.
+ @param Mapping A resulting value to pass to Unmap().
+
+ @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes.
+ @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common buffer.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_DEVICE_ERROR The system hardware could not map the requested address.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_MAP)(
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION Operation,
+ IN VOID *HostAddress,
+ IN OUT UINTN *NumberOfBytes,
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
+ OUT VOID **Mapping
+ );
+
+/**
+ Completes the Map() operation and releases any corresponding resources.
+
+ @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+ @param Mapping The mapping value returned from Map().
+
+ @retval EFI_SUCCESS The range was unmapped.
+ @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by Map().
+ @retval EFI_DEVICE_ERROR The data was not committed to the target system memory.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_UNMAP)(
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN VOID *Mapping
+ );
+
+/**
+ Allocates pages that are suitable for an EfiPciOperationBusMasterCommonBuffer or
+ EfiPciOperationBusMasterCommonBuffer64 mapping.
+
+ @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+ @param Type This parameter is not used and must be ignored.
+ @param MemoryType The type of memory to allocate, EfiBootServicesData or
+ EfiRuntimeServicesData.
+ @param Pages The number of pages to allocate.
+ @param HostAddress A pointer to store the base system memory address of the
+ allocated range.
+ @param Attributes The requested bit mask of attributes for the allocated range.
+
+ @retval EFI_SUCCESS The requested memory pages were allocated.
+ @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are
+ MEMORY_WRITE_COMBINE and MEMORY_CACHED.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_ALLOCATE_BUFFER)(
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN EFI_ALLOCATE_TYPE Type,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN Pages,
+ IN OUT VOID **HostAddress,
+ IN UINT64 Attributes
+ );
+
+/**
+ Frees memory that was allocated with AllocateBuffer().
+
+ @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+ @param Pages The number of pages to free.
+ @param HostAddress The base system memory address of the allocated range.
+
+ @retval EFI_SUCCESS The requested memory pages were freed.
+ @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages
+ was not allocated with AllocateBuffer().
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_FREE_BUFFER)(
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN UINTN Pages,
+ IN VOID *HostAddress
+ );
+
+/**
+ Flushes all PCI posted write transactions from a PCI host bridge to system memory.
+
+ @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+
+ @retval EFI_SUCCESS The PCI posted write transactions were flushed from the PCI host
+ bridge to system memory.
+ @retval EFI_DEVICE_ERROR The PCI posted write transactions were not flushed from the PCI
+ host bridge due to a hardware error.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_FLUSH)(
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This
+ );
+
+/**
+ Gets the attributes that a PCI root bridge supports setting with SetAttributes(), and the
+ attributes that a PCI root bridge is currently using.
+
+ @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+ @param Supports A pointer to the mask of attributes that this PCI root bridge supports
+ setting with SetAttributes().
+ @param Attributes A pointer to the mask of attributes that this PCI root bridge is currently
+ using.
+
+ @retval EFI_SUCCESS If Supports is not NULL, then the attributes that the PCI root
+ bridge supports is returned in Supports. If Attributes is
+ not NULL, then the attributes that the PCI root bridge is currently
+ using is returned in Attributes.
+ @retval EFI_INVALID_PARAMETER Both Supports and Attributes are NULL.
+
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_GET_ATTRIBUTES)(
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ OUT UINT64 *Supports,
+ OUT UINT64 *Attributes
+ );
+
+/**
+ Sets attributes for a resource range on a PCI root bridge.
+
+ @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+ @param Attributes The mask of attributes to set.
+ @param ResourceBase A pointer to the base address of the resource range to be modified by the
+ attributes specified by Attributes.
+ @param ResourceLength A pointer to the length of the resource range to be modified by the
+ attributes specified by Attributes.
+
+ @retval EFI_SUCCESS The set of attributes specified by Attributes for the resource
+ range specified by ResourceBase and ResourceLength
+ were set on the PCI root bridge, and the actual resource range is
+ returned in ResuourceBase and ResourceLength.
+ @retval EFI_UNSUPPORTED A bit is set in Attributes that is not supported by the PCI Root
+ Bridge.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources to set the attributes on the
+ resource range specified by BaseAddress and Length.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_SET_ATTRIBUTES)(
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN UINT64 Attributes,
+ IN OUT UINT64 *ResourceBase,
+ IN OUT UINT64 *ResourceLength
+ );
+
+/**
+ Retrieves the current resource settings of this PCI root bridge in the form of a set of ACPI 2.0
+ resource descriptors.
+
+ @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+ @param Resources A pointer to the ACPI 2.0 resource descriptors that describe the current
+ configuration of this PCI root bridge.
+
+ @retval EFI_SUCCESS The current configuration of this PCI root bridge was returned in
+ Resources.
+ @retval EFI_UNSUPPORTED The current configuration of this PCI root bridge could not be
+ retrieved.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_CONFIGURATION)(
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ OUT VOID **Resources
+ );
+
+/**
+ @par Protocol Description:
+ Provides the basic Memory, I/O, PCI configuration, and DMA interfaces that are
+ used to abstract accesses to PCI controllers behind a PCI Root Bridge Controller.
+
+ @param ParentHandle
+ The EFI_HANDLE of the PCI Host Bridge of which this PCI Root Bridge is a member.
+
+ @param PollMem
+ Polls an address in memory mapped I/O space until an exit condition is met,
+ or a timeout occurs.
+
+ @param PollIo
+ Polls an address in I/O space until an exit condition is met, or a timeout occurs.
+
+ @param Mem.Read
+ Allows reads from memory mapped I/O space.
+
+ @param Mem.Write
+ Allows writes to memory mapped I/O space.
+
+ @param Io.Read
+ Allows reads from I/O space.
+
+ @param Io.Write
+ Allows writes to I/O space.
+
+ @param Pci.Read
+ Allows reads from PCI configuration space.
+
+ @param Pci.Write
+ Allows writes to PCI configuration space.
+
+ @param CopyMem
+ Allows one region of PCI root bridge memory space to be copied to another
+ region of PCI root bridge memory space.
+
+ @param Map
+ Provides the PCI controller's specific addresses needed to access system memory for DMA.
+
+ @param Unmap
+ Releases any resources allocated by Map().
+
+ @param AllocateBuffer
+ Allocates pages that are suitable for a common buffer mapping.
+
+ @param FreeBuffer
+ Free pages that were allocated with AllocateBuffer().
+
+ @param Flush
+ Flushes all PCI posted write transactions to system memory.
+
+ @param GetAttributes
+ Gets the attributes that a PCI root bridge supports setting with SetAttributes(),
+ and the attributes that a PCI root bridge is currently using.
+
+ @param SetAttributes
+ Sets attributes for a resource range on a PCI root bridge.
+
+ @param Configuration
+ Gets the current resource settings for this PCI root bridge.
+
+ @param SegmentNumber
+ The segment number that this PCI root bridge resides.
+
+**/
+struct _EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL {
+ EFI_HANDLE ParentHandle;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_POLL_IO_MEM PollMem;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_POLL_IO_MEM PollIo;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_ACCESS Mem;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_ACCESS Io;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_ACCESS Pci;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_COPY_MEM CopyMem;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_MAP Map;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_UNMAP Unmap;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_ALLOCATE_BUFFER AllocateBuffer;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_FREE_BUFFER FreeBuffer;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_FLUSH Flush;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_GET_ATTRIBUTES GetAttributes;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_SET_ATTRIBUTES SetAttributes;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_CONFIGURATION Configuration;
+ UINT32 SegmentNumber;
+};
+
+extern EFI_GUID gEfiPciRootBridgeIoProtocolGuid;
+
+#endif
diff --git a/gpxe/src/include/gpxe/efi/Protocol/SimpleNetwork.h b/gpxe/src/include/gpxe/efi/Protocol/SimpleNetwork.h
new file mode 100644
index 00000000..ed8c8ce6
--- /dev/null
+++ b/gpxe/src/include/gpxe/efi/Protocol/SimpleNetwork.h
@@ -0,0 +1,645 @@
+/** @file
+ Simple Network protocol as defined in the UEFI 2.0 specification.
+
+ Basic network device abstraction.
+
+ Rx - Received
+ Tx - Transmit
+ MCast - MultiCast
+ ...
+
+ Copyright (c) 2006 - 2008, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __SIMPLE_NETWORK_H__
+#define __SIMPLE_NETWORK_H__
+
+#define EFI_SIMPLE_NETWORK_PROTOCOL_GUID \
+ { \
+ 0xA19832B9, 0xAC25, 0x11D3, {0x9A, 0x2D, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D } \
+ }
+
+typedef struct _EFI_SIMPLE_NETWORK_PROTOCOL EFI_SIMPLE_NETWORK_PROTOCOL;
+
+
+///
+/// Protocol defined in EFI1.1.
+///
+typedef EFI_SIMPLE_NETWORK_PROTOCOL EFI_SIMPLE_NETWORK;
+
+///
+/// Simple Network Protocol data structures
+///
+typedef struct {
+ ///
+ /// Total number of frames received. Includes frames with errors and
+ /// dropped frames.
+ ///
+ UINT64 RxTotalFrames;
+
+ ///
+ /// Number of valid frames received and copied into receive buffers.
+ ///
+ UINT64 RxGoodFrames;
+
+ ///
+ /// Number of frames below the minimum length for the media.
+ /// This would be <64 for ethernet.
+ ///
+ UINT64 RxUndersizeFrames;
+
+ ///
+ /// Number of frames longer than the maxminum length for the
+ /// media. This would be >1500 for ethernet.
+ ///
+ UINT64 RxOversizeFrames;
+
+ ///
+ /// Valid frames that were dropped because receive buffers were full.
+ ///
+ UINT64 RxDroppedFrames;
+
+ ///
+ /// Number of valid unicast frames received and not dropped.
+ ///
+ UINT64 RxUnicastFrames;
+
+ ///
+ /// Number of valid broadcast frames received and not dropped.
+ ///
+ UINT64 RxBroadcastFrames;
+
+ ///
+ /// Number of valid mutlicast frames received and not dropped.
+ ///
+ UINT64 RxMulticastFrames;
+
+ ///
+ /// Number of frames w/ CRC or alignment errors.
+ ///
+ UINT64 RxCrcErrorFrames;
+
+ ///
+ /// Total number of bytes received. Includes frames with errors
+ /// and dropped frames.
+ //
+ UINT64 RxTotalBytes;
+
+ ///
+ /// Transmit statistics.
+ ///
+ UINT64 TxTotalFrames;
+ UINT64 TxGoodFrames;
+ UINT64 TxUndersizeFrames;
+ UINT64 TxOversizeFrames;
+ UINT64 TxDroppedFrames;
+ UINT64 TxUnicastFrames;
+ UINT64 TxBroadcastFrames;
+ UINT64 TxMulticastFrames;
+ UINT64 TxCrcErrorFrames;
+ UINT64 TxTotalBytes;
+
+ ///
+ /// Number of collisions detection on this subnet.
+ ///
+ UINT64 Collisions;
+
+ ///
+ /// Number of frames destined for unsupported protocol.
+ ///
+ UINT64 UnsupportedProtocol;
+
+} EFI_NETWORK_STATISTICS;
+
+typedef enum {
+ EfiSimpleNetworkStopped,
+ EfiSimpleNetworkStarted,
+ EfiSimpleNetworkInitialized,
+ EfiSimpleNetworkMaxState
+} EFI_SIMPLE_NETWORK_STATE;
+
+#define EFI_SIMPLE_NETWORK_RECEIVE_UNICAST 0x01
+#define EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST 0x02
+#define EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST 0x04
+#define EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS 0x08
+#define EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST 0x10
+
+#define EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT 0x01
+#define EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT 0x02
+#define EFI_SIMPLE_NETWORK_COMMAND_INTERRUPT 0x04
+#define EFI_SIMPLE_NETWORK_SOFTWARE_INTERRUPT 0x08
+
+#define MAX_MCAST_FILTER_CNT 16
+typedef struct {
+ UINT32 State;
+ UINT32 HwAddressSize;
+ UINT32 MediaHeaderSize;
+ UINT32 MaxPacketSize;
+ UINT32 NvRamSize;
+ UINT32 NvRamAccessSize;
+ UINT32 ReceiveFilterMask;
+ UINT32 ReceiveFilterSetting;
+ UINT32 MaxMCastFilterCount;
+ UINT32 MCastFilterCount;
+ EFI_MAC_ADDRESS MCastFilter[MAX_MCAST_FILTER_CNT];
+ EFI_MAC_ADDRESS CurrentAddress;
+ EFI_MAC_ADDRESS BroadcastAddress;
+ EFI_MAC_ADDRESS PermanentAddress;
+ UINT8 IfType;
+ BOOLEAN MacAddressChangeable;
+ BOOLEAN MultipleTxSupported;
+ BOOLEAN MediaPresentSupported;
+ BOOLEAN MediaPresent;
+} EFI_SIMPLE_NETWORK_MODE;
+
+//
+// Protocol Member Functions
+//
+/**
+ Changes the state of a network interface from "stopped" to "started".
+
+ @param This Protocol instance pointer.
+
+ @retval EFI_SUCCESS The network interface was started.
+ @retval EFI_ALREADY_STARTED The network interface is already in the started state.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network interface.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SIMPLE_NETWORK_START)(
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This
+ );
+
+/**
+ Changes the state of a network interface from "started" to "stopped".
+
+ @param This Protocol instance pointer.
+
+ @retval EFI_SUCCESS The network interface was stopped.
+ @retval EFI_ALREADY_STARTED The network interface is already in the stopped state.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network interface.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SIMPLE_NETWORK_STOP)(
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This
+ );
+
+/**
+ Resets a network adapter and allocates the transmit and receive buffers
+ required by the network interface; optionally, also requests allocation
+ of additional transmit and receive buffers.
+
+ @param This Protocol instance pointer.
+ @param ExtraRxBufferSize The size, in bytes, of the extra receive buffer space
+ that the driver should allocate for the network interface.
+ Some network interfaces will not be able to use the extra
+ buffer, and the caller will not know if it is actually
+ being used.
+ @param ExtraTxBufferSize The size, in bytes, of the extra transmit buffer space
+ that the driver should allocate for the network interface.
+ Some network interfaces will not be able to use the extra
+ buffer, and the caller will not know if it is actually
+ being used.
+
+ @retval EFI_SUCCESS The network interface was initialized.
+ @retval EFI_NOT_STARTED The network interface has not been started
+ @retval EFI_OUT_OF_RESOURCES There was not enough memory for the transmit and
+ receive buffers. .
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network interface.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SIMPLE_NETWORK_INITIALIZE)(
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN UINTN ExtraRxBufferSize OPTIONAL,
+ IN UINTN ExtraTxBufferSize OPTIONAL
+ );
+
+/**
+ Resets a network adapter and re-initializes it with the parameters that were
+ provided in the previous call to Initialize().
+
+ @param This Protocol instance pointer.
+ @param ExtendedVerification Indicates that the driver may perform a more
+ exhaustive verification operation of the device
+ during reset.
+
+ @retval EFI_SUCCESS The network interface was reset.
+ @retval EFI_NOT_STARTED The network interface has not been started
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network interface.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SIMPLE_NETWORK_RESET)(
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ );
+
+/**
+ Resets a network adapter and leaves it in a state that is safe for
+ another driver to initialize.
+
+ @param This Protocol instance pointer.
+
+ @retval EFI_SUCCESS The network interface was shutdown.
+ @retval EFI_NOT_STARTED The network interface has not been started
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network interface.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SIMPLE_NETWORK_SHUTDOWN)(
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This
+ );
+
+/**
+ Manages the multicast receive filters of a network interface.
+
+ @param This Protocol instance pointer.
+ @param Enable A bit mask of receive filters to enable on the network interface.
+ @param Disable A bit mask of receive filters to disable on the network interface.
+ @param ResetMCastFilter Set to TRUE to reset the contents of the multicast receive
+ filters on the network interface to their default values.
+ @param McastFilterCnt Number of multicast HW MAC addresses in the new
+ MCastFilter list. This value must be less than or equal to
+ the MCastFilterCnt field of EFI_SIMPLE_NETWORK_MODE. This
+ field is optional if ResetMCastFilter is TRUE.
+ @param MCastFilter A pointer to a list of new multicast receive filter HW MAC
+ addresses. This list will replace any existing multicast
+ HW MAC address list. This field is optional if
+ ResetMCastFilter is TRUE.
+
+ @retval EFI_SUCCESS The multicast receive filter list was updated.
+ @retval EFI_NOT_STARTED The network interface has not been started
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network interface.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SIMPLE_NETWORK_RECEIVE_FILTERS)(
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN UINT32 Enable,
+ IN UINT32 Disable,
+ IN BOOLEAN ResetMCastFilter,
+ IN UINTN MCastFilterCnt OPTIONAL,
+ IN EFI_MAC_ADDRESS *MCastFilter OPTIONAL
+ );
+
+/**
+ Modifies or resets the current station address, if supported.
+
+ @param This Protocol instance pointer.
+ @param Reset Flag used to reset the station address to the network interfaces
+ permanent address.
+ @param New New station address to be used for the network interface.
+
+ @retval EFI_SUCCESS The network interfaces station address was updated.
+ @retval EFI_NOT_STARTED The network interface has not been started
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network interface.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SIMPLE_NETWORK_STATION_ADDRESS)(
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN BOOLEAN Reset,
+ IN EFI_MAC_ADDRESS *New OPTIONAL
+ );
+
+/**
+ Resets or collects the statistics on a network interface.
+
+ @param This Protocol instance pointer.
+ @param Reset Set to TRUE to reset the statistics for the network interface.
+ @param StatisticsSize On input the size, in bytes, of StatisticsTable. On
+ output the size, in bytes, of the resulting table of
+ statistics.
+ @param StatisticsTable A pointer to the EFI_NETWORK_STATISTICS structure that
+ contains the statistics.
+
+ @retval EFI_SUCCESS The statistics were collected from the network interface.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_BUFFER_TOO_SMALL The Statistics buffer was too small. The current buffer
+ size needed to hold the statistics is returned in
+ StatisticsSize.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network interface.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SIMPLE_NETWORK_STATISTICS)(
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN BOOLEAN Reset,
+ IN OUT UINTN *StatisticsSize OPTIONAL,
+ OUT EFI_NETWORK_STATISTICS *StatisticsTable OPTIONAL
+ );
+
+/**
+ Converts a multicast IP address to a multicast HW MAC address.
+
+ @param This Protocol instance pointer.
+ @param IPv6 Set to TRUE if the multicast IP address is IPv6 [RFC 2460]. Set
+ to FALSE if the multicast IP address is IPv4 [RFC 791].
+ @param IP The multicast IP address that is to be converted to a multicast
+ HW MAC address.
+ @param MAC The multicast HW MAC address that is to be generated from IP.
+
+ @retval EFI_SUCCESS The multicast IP address was mapped to the multicast
+ HW MAC address.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_BUFFER_TOO_SMALL The Statistics buffer was too small. The current buffer
+ size needed to hold the statistics is returned in
+ StatisticsSize.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network interface.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SIMPLE_NETWORK_MCAST_IP_TO_MAC)(
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN BOOLEAN IPv6,
+ IN EFI_IP_ADDRESS *IP,
+ OUT EFI_MAC_ADDRESS *MAC
+ );
+
+/**
+ Performs read and write operations on the NVRAM device attached to a
+ network interface.
+
+ @param This Protocol instance pointer.
+ @param ReadWrite TRUE for read operations, FALSE for write operations.
+ @param Offset Byte offset in the NVRAM device at which to start the read or
+ write operation. This must be a multiple of NvRamAccessSize and
+ less than NvRamSize.
+ @param BufferSize The number of bytes to read or write from the NVRAM device.
+ This must also be a multiple of NvramAccessSize.
+ @param Buffer A pointer to the data buffer.
+
+ @retval EFI_SUCCESS The NVRAM access was performed.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network interface.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SIMPLE_NETWORK_NVDATA)(
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN BOOLEAN ReadWrite,
+ IN UINTN Offset,
+ IN UINTN BufferSize,
+ IN OUT VOID *Buffer
+ );
+
+/**
+ Reads the current interrupt status and recycled transmit buffer status from
+ a network interface.
+
+ @param This Protocol instance pointer.
+ @param InterruptStatus A pointer to the bit mask of the currently active interrupts
+ If this is NULL, the interrupt status will not be read from
+ the device. If this is not NULL, the interrupt status will
+ be read from the device. When the interrupt status is read,
+ it will also be cleared. Clearing the transmit interrupt
+ does not empty the recycled transmit buffer array.
+ @param TxBuf Recycled transmit buffer address. The network interface will
+ not transmit if its internal recycled transmit buffer array
+ is full. Reading the transmit buffer does not clear the
+ transmit interrupt. If this is NULL, then the transmit buffer
+ status will not be read. If there are no transmit buffers to
+ recycle and TxBuf is not NULL, * TxBuf will be set to NULL.
+
+ @retval EFI_SUCCESS The status of the network interface was retrieved.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network interface.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SIMPLE_NETWORK_GET_STATUS)(
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ OUT UINT32 *InterruptStatus OPTIONAL,
+ OUT VOID **TxBuf OPTIONAL
+ );
+
+/**
+ Places a packet in the transmit queue of a network interface.
+
+ @param This Protocol instance pointer.
+ @param HeaderSize The size, in bytes, of the media header to be filled in by
+ the Transmit() function. If HeaderSize is non-zero, then it
+ must be equal to This->Mode->MediaHeaderSize and the DestAddr
+ and Protocol parameters must not be NULL.
+ @param BufferSize The size, in bytes, of the entire packet (media header and
+ data) to be transmitted through the network interface.
+ @param Buffer A pointer to the packet (media header followed by data) to be
+ transmitted. This parameter cannot be NULL. If HeaderSize is zero,
+ then the media header in Buffer must already be filled in by the
+ caller. If HeaderSize is non-zero, then the media header will be
+ filled in by the Transmit() function.
+ @param SrcAddr The source HW MAC address. If HeaderSize is zero, then this parameter
+ is ignored. If HeaderSize is non-zero and SrcAddr is NULL, then
+ This->Mode->CurrentAddress is used for the source HW MAC address.
+ @param DsetAddr The destination HW MAC address. If HeaderSize is zero, then this
+ parameter is ignored.
+ @param Protocol The type of header to build. If HeaderSize is zero, then this
+ parameter is ignored. See RFC 1700, section "Ether Types", for
+ examples.
+
+ @retval EFI_SUCCESS The packet was placed on the transmit queue.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_NOT_READY The network interface is too busy to accept this transmit request.
+ @retval EFI_BUFFER_TOO_SMALL The BufferSize parameter is too small.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network interface.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SIMPLE_NETWORK_TRANSMIT)(
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN UINTN HeaderSize,
+ IN UINTN BufferSize,
+ IN VOID *Buffer,
+ IN EFI_MAC_ADDRESS *SrcAddr OPTIONAL,
+ IN EFI_MAC_ADDRESS *DestAddr OPTIONAL,
+ IN UINT16 *Protocol OPTIONAL
+ );
+
+/**
+ Receives a packet from a network interface.
+
+ @param This Protocol instance pointer.
+ @param HeaderSize The size, in bytes, of the media header received on the network
+ interface. If this parameter is NULL, then the media header size
+ will not be returned.
+ @param BufferSize On entry, the size, in bytes, of Buffer. On exit, the size, in
+ bytes, of the packet that was received on the network interface.
+ @param Buffer A pointer to the data buffer to receive both the media header and
+ the data.
+ @param SrcAddr The source HW MAC address. If this parameter is NULL, the
+ HW MAC source address will not be extracted from the media
+ header.
+ @param DsetAddr The destination HW MAC address. If this parameter is NULL,
+ the HW MAC destination address will not be extracted from the
+ media header.
+ @param Protocol The media header type. If this parameter is NULL, then the
+ protocol will not be extracted from the media header. See
+ RFC 1700 section "Ether Types" for examples.
+
+ @retval EFI_SUCCESS The received data was stored in Buffer, and BufferSize has
+ been updated to the number of bytes received.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_NOT_READY The network interface is too busy to accept this transmit
+ request.
+ @retval EFI_BUFFER_TOO_SMALL The BufferSize parameter is too small.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network interface.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SIMPLE_NETWORK_RECEIVE)(
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ OUT UINTN *HeaderSize OPTIONAL,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer,
+ OUT EFI_MAC_ADDRESS *SrcAddr OPTIONAL,
+ OUT EFI_MAC_ADDRESS *DestAddr OPTIONAL,
+ OUT UINT16 *Protocol OPTIONAL
+ );
+
+#define EFI_SIMPLE_NETWORK_PROTOCOL_REVISION 0x00010000
+
+//
+// Revision defined in EFI1.1
+//
+#define EFI_SIMPLE_NETWORK_INTERFACE_REVISION EFI_SIMPLE_NETWORK_PROTOCOL_REVISION
+
+/**
+ @par Protocol Description:
+ The EFI_SIMPLE_NETWORK_PROTOCOL protocol is used to initialize access
+ to a network adapter. Once the network adapter initializes,
+ the EFI_SIMPLE_NETWORK_PROTOCOL protocol provides services that
+ allow packets to be transmitted and received.
+
+ @param Revision
+ Revision of the EFI_SIMPLE_NETWORK_PROTOCOL. All future revisions must
+ be backwards compatible. If a future version is not backwards compatible
+ it is not the same GUID.
+
+ @param Start
+ Prepares the network interface for further command operations.
+ No other EFI_SIMPLE_NETWORK_PROTOCOL interface functions will operate
+ until this call is made.
+
+ @param Stop
+ Stops further network interface command processing.
+ No other EFI_SIMPLE_NETWORK_PROTOCOL interface functions will operate
+ after this call is made until another Start() call is made.
+
+ @param Initialize
+ Resets the network adapter and allocates the transmit and receive buffers.
+
+ @param Reset
+ Resets the network adapter and reinitializes it with the parameters
+ provided in the previous call to Initialize().
+
+ @param Shutdown
+ Resets the network adapter and leaves it in a state safe for another driver
+ to initialize. The memory buffers assigned in the Initialize() call are released.
+ After this call, only the Initialize() or Stop() calls may be used.
+
+ @param ReceiveFilters
+ Enables and disables the receive filters for the network interface and,
+ if supported, manages the filtered multicast
+ HW MAC (Hardware Media Access Control) address list.
+
+ @param StationAddress
+ Modifies or resets the current station address, if supported.
+
+ @param Statistics
+ Collects statistics from the network interface and allows the statistics to be reset.
+
+ @param MCastIpToMac
+ Maps a multicast IP address to a multicast HW MAC address.
+
+ @param NvData
+ Reads and writes the contents of the NVRAM devices attached to the network interface.
+
+ @param GetStatus
+ Reads the current interrupt status and the list of recycled transmit
+ buffers from the network interface.
+
+ @param Transmit
+ Places a packet in the transmit queue.
+
+ @param Receive
+ Retrieves a packet from the receive queue, along with the status
+ flags that describe the packet type.
+
+ @param WaitForPacket
+ Event used with WaitForEvent() to wait for a packet to be received.
+
+ @param Mode
+ Pointer to the EFI_SIMPLE_NETWORK_MODE data for the device.
+
+**/
+struct _EFI_SIMPLE_NETWORK_PROTOCOL {
+ UINT64 Revision;
+ EFI_SIMPLE_NETWORK_START Start;
+ EFI_SIMPLE_NETWORK_STOP Stop;
+ EFI_SIMPLE_NETWORK_INITIALIZE Initialize;
+ EFI_SIMPLE_NETWORK_RESET Reset;
+ EFI_SIMPLE_NETWORK_SHUTDOWN Shutdown;
+ EFI_SIMPLE_NETWORK_RECEIVE_FILTERS ReceiveFilters;
+ EFI_SIMPLE_NETWORK_STATION_ADDRESS StationAddress;
+ EFI_SIMPLE_NETWORK_STATISTICS Statistics;
+ EFI_SIMPLE_NETWORK_MCAST_IP_TO_MAC MCastIpToMac;
+ EFI_SIMPLE_NETWORK_NVDATA NvData;
+ EFI_SIMPLE_NETWORK_GET_STATUS GetStatus;
+ EFI_SIMPLE_NETWORK_TRANSMIT Transmit;
+ EFI_SIMPLE_NETWORK_RECEIVE Receive;
+ EFI_EVENT WaitForPacket;
+ EFI_SIMPLE_NETWORK_MODE *Mode;
+};
+
+extern EFI_GUID gEfiSimpleNetworkProtocolGuid;
+
+#endif
diff --git a/gpxe/src/include/gpxe/efi/Protocol/SimpleTextIn.h b/gpxe/src/include/gpxe/efi/Protocol/SimpleTextIn.h
new file mode 100644
index 00000000..ca747dde
--- /dev/null
+++ b/gpxe/src/include/gpxe/efi/Protocol/SimpleTextIn.h
@@ -0,0 +1,145 @@
+/** @file
+ Simple Text In protocol from the UEFI 2.0 specification.
+
+ Abstraction of a very simple input device like a keyboard or serial
+ terminal.
+
+ Copyright (c) 2006 - 2008, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __SIMPLE_TEXT_IN_PROTOCOL_H__
+#define __SIMPLE_TEXT_IN_PROTOCOL_H__
+
+#include <gpxe/efi/ProcessorBind.h>
+
+#define EFI_SIMPLE_TEXT_INPUT_PROTOCOL_GUID \
+ { \
+ 0x387477c1, 0x69c7, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b } \
+ }
+
+///
+/// Protocol GUID defined in EFI1.1.
+///
+#define SIMPLE_INPUT_PROTOCOL EFI_SIMPLE_TEXT_INPUT_PROTOCOL_GUID
+
+typedef struct _EFI_SIMPLE_TEXT_INPUT_PROTOCOL EFI_SIMPLE_TEXT_INPUT_PROTOCOL;
+
+///
+/// Backward-compatible with EFI1.1.
+///
+typedef struct _EFI_SIMPLE_TEXT_INPUT_PROTOCOL SIMPLE_INPUT_INTERFACE;
+//
+// Data structures
+//
+typedef struct {
+ UINT16 ScanCode;
+ CHAR16 UnicodeChar;
+} EFI_INPUT_KEY;
+
+//
+// Required unicode control chars
+//
+#define CHAR_NULL 0x0000
+#define CHAR_BACKSPACE 0x0008
+#define CHAR_TAB 0x0009
+#define CHAR_LINEFEED 0x000A
+#define CHAR_CARRIAGE_RETURN 0x000D
+
+//
+// EFI Scan codes
+//
+#define SCAN_NULL 0x0000
+#define SCAN_UP 0x0001
+#define SCAN_DOWN 0x0002
+#define SCAN_RIGHT 0x0003
+#define SCAN_LEFT 0x0004
+#define SCAN_HOME 0x0005
+#define SCAN_END 0x0006
+#define SCAN_INSERT 0x0007
+#define SCAN_DELETE 0x0008
+#define SCAN_PAGE_UP 0x0009
+#define SCAN_PAGE_DOWN 0x000A
+#define SCAN_F1 0x000B
+#define SCAN_F2 0x000C
+#define SCAN_F3 0x000D
+#define SCAN_F4 0x000E
+#define SCAN_F5 0x000F
+#define SCAN_F6 0x0010
+#define SCAN_F7 0x0011
+#define SCAN_F8 0x0012
+#define SCAN_F9 0x0013
+#define SCAN_F10 0x0014
+#define SCAN_F11 0x0015
+#define SCAN_F12 0x0016
+#define SCAN_ESC 0x0017
+
+/**
+ Reset the input device and optionaly run diagnostics
+
+ @param This Protocol instance pointer.
+ @param ExtendedVerification Driver may perform diagnostics on reset.
+
+ @retval EFI_SUCCESS The device was reset.
+ @retval EFI_DEVICE_ERROR The device is not functioning properly and could not be reset.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_INPUT_RESET)(
+ IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ );
+
+/**
+ Reads the next keystroke from the input device. The WaitForKey Event can
+ be used to test for existance of a keystroke via WaitForEvent () call.
+
+ @param This Protocol instance pointer.
+ @param Key Driver may perform diagnostics on reset.
+
+ @retval EFI_SUCCESS The keystroke information was returned.
+ @retval EFI_NOT_READY There was no keystroke data availiable.
+ @retval EFI_DEVICE_ERROR The keydtroke information was not returned due to
+ hardware errors.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_INPUT_READ_KEY)(
+ IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
+ OUT EFI_INPUT_KEY *Key
+ );
+
+/**
+ @par Protocol Description:
+ The EFI_SIMPLE_TEXT_INPUT_PROTOCOL is used on the ConsoleIn device.
+ It is the minimum required protocol for ConsoleIn.
+
+ @param Reset
+ Reset the ConsoleIn device.
+
+ @param ReadKeyStroke
+ Returns the next input character.
+
+ @param WaitForKey
+ Event to use with WaitForEvent() to wait for a key to be available.
+
+**/
+
+struct _EFI_SIMPLE_TEXT_INPUT_PROTOCOL {
+ EFI_INPUT_RESET Reset;
+ EFI_INPUT_READ_KEY ReadKeyStroke;
+ EFI_EVENT WaitForKey;
+};
+
+extern EFI_GUID gEfiSimpleTextInProtocolGuid;
+
+#endif
diff --git a/gpxe/src/include/gpxe/efi/Protocol/SimpleTextOut.h b/gpxe/src/include/gpxe/efi/Protocol/SimpleTextOut.h
new file mode 100644
index 00000000..cc772743
--- /dev/null
+++ b/gpxe/src/include/gpxe/efi/Protocol/SimpleTextOut.h
@@ -0,0 +1,437 @@
+/** @file
+ Simple Text Out protocol from the UEFI 2.0 specification.
+
+ Abstraction of a very simple text based output device like VGA text mode or
+ a serial terminal. The Simple Text Out protocol instance can represent
+ a single hardware device or a virtual device that is an agregation
+ of multiple physical devices.
+
+ Copyright (c) 2006 - 2008, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __SIMPLE_TEXT_OUT_H__
+#define __SIMPLE_TEXT_OUT_H__
+
+#include <gpxe/efi/PiDxe.h>
+
+#define EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_GUID \
+ { \
+ 0x387477c2, 0x69c7, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b } \
+ }
+
+///
+/// Protocol GUID defined in EFI1.1.
+///
+#define SIMPLE_TEXT_OUTPUT_PROTOCOL EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_GUID
+
+typedef struct _EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL;
+
+///
+/// Backward-compatible with EFI1.1.
+///
+typedef EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL SIMPLE_TEXT_OUTPUT_INTERFACE;
+
+//
+// Define's for required EFI Unicode Box Draw characters
+//
+#define BOXDRAW_HORIZONTAL 0x2500
+#define BOXDRAW_VERTICAL 0x2502
+#define BOXDRAW_DOWN_RIGHT 0x250c
+#define BOXDRAW_DOWN_LEFT 0x2510
+#define BOXDRAW_UP_RIGHT 0x2514
+#define BOXDRAW_UP_LEFT 0x2518
+#define BOXDRAW_VERTICAL_RIGHT 0x251c
+#define BOXDRAW_VERTICAL_LEFT 0x2524
+#define BOXDRAW_DOWN_HORIZONTAL 0x252c
+#define BOXDRAW_UP_HORIZONTAL 0x2534
+#define BOXDRAW_VERTICAL_HORIZONTAL 0x253c
+#define BOXDRAW_DOUBLE_HORIZONTAL 0x2550
+#define BOXDRAW_DOUBLE_VERTICAL 0x2551
+#define BOXDRAW_DOWN_RIGHT_DOUBLE 0x2552
+#define BOXDRAW_DOWN_DOUBLE_RIGHT 0x2553
+#define BOXDRAW_DOUBLE_DOWN_RIGHT 0x2554
+#define BOXDRAW_DOWN_LEFT_DOUBLE 0x2555
+#define BOXDRAW_DOWN_DOUBLE_LEFT 0x2556
+#define BOXDRAW_DOUBLE_DOWN_LEFT 0x2557
+#define BOXDRAW_UP_RIGHT_DOUBLE 0x2558
+#define BOXDRAW_UP_DOUBLE_RIGHT 0x2559
+#define BOXDRAW_DOUBLE_UP_RIGHT 0x255a
+#define BOXDRAW_UP_LEFT_DOUBLE 0x255b
+#define BOXDRAW_UP_DOUBLE_LEFT 0x255c
+#define BOXDRAW_DOUBLE_UP_LEFT 0x255d
+#define BOXDRAW_VERTICAL_RIGHT_DOUBLE 0x255e
+#define BOXDRAW_VERTICAL_DOUBLE_RIGHT 0x255f
+#define BOXDRAW_DOUBLE_VERTICAL_RIGHT 0x2560
+#define BOXDRAW_VERTICAL_LEFT_DOUBLE 0x2561
+#define BOXDRAW_VERTICAL_DOUBLE_LEFT 0x2562
+#define BOXDRAW_DOUBLE_VERTICAL_LEFT 0x2563
+#define BOXDRAW_DOWN_HORIZONTAL_DOUBLE 0x2564
+#define BOXDRAW_DOWN_DOUBLE_HORIZONTAL 0x2565
+#define BOXDRAW_DOUBLE_DOWN_HORIZONTAL 0x2566
+#define BOXDRAW_UP_HORIZONTAL_DOUBLE 0x2567
+#define BOXDRAW_UP_DOUBLE_HORIZONTAL 0x2568
+#define BOXDRAW_DOUBLE_UP_HORIZONTAL 0x2569
+#define BOXDRAW_VERTICAL_HORIZONTAL_DOUBLE 0x256a
+#define BOXDRAW_VERTICAL_DOUBLE_HORIZONTAL 0x256b
+#define BOXDRAW_DOUBLE_VERTICAL_HORIZONTAL 0x256c
+
+//
+// EFI Required Block Elements Code Chart
+//
+#define BLOCKELEMENT_FULL_BLOCK 0x2588
+#define BLOCKELEMENT_LIGHT_SHADE 0x2591
+
+//
+// EFI Required Geometric Shapes Code Chart
+//
+#define GEOMETRICSHAPE_UP_TRIANGLE 0x25b2
+#define GEOMETRICSHAPE_RIGHT_TRIANGLE 0x25ba
+#define GEOMETRICSHAPE_DOWN_TRIANGLE 0x25bc
+#define GEOMETRICSHAPE_LEFT_TRIANGLE 0x25c4
+
+//
+// EFI Required Arrow shapes
+//
+#define ARROW_LEFT 0x2190
+#define ARROW_UP 0x2191
+#define ARROW_RIGHT 0x2192
+#define ARROW_DOWN 0x2193
+
+//
+// EFI Console Colours
+//
+#define EFI_BLACK 0x00
+#define EFI_BLUE 0x01
+#define EFI_GREEN 0x02
+#define EFI_CYAN (EFI_BLUE | EFI_GREEN)
+#define EFI_RED 0x04
+#define EFI_MAGENTA (EFI_BLUE | EFI_RED)
+#define EFI_BROWN (EFI_GREEN | EFI_RED)
+#define EFI_LIGHTGRAY (EFI_BLUE | EFI_GREEN | EFI_RED)
+#define EFI_BRIGHT 0x08
+#define EFI_DARKGRAY (EFI_BRIGHT)
+#define EFI_LIGHTBLUE (EFI_BLUE | EFI_BRIGHT)
+#define EFI_LIGHTGREEN (EFI_GREEN | EFI_BRIGHT)
+#define EFI_LIGHTCYAN (EFI_CYAN | EFI_BRIGHT)
+#define EFI_LIGHTRED (EFI_RED | EFI_BRIGHT)
+#define EFI_LIGHTMAGENTA (EFI_MAGENTA | EFI_BRIGHT)
+#define EFI_YELLOW (EFI_BROWN | EFI_BRIGHT)
+#define EFI_WHITE (EFI_BLUE | EFI_GREEN | EFI_RED | EFI_BRIGHT)
+
+#define EFI_TEXT_ATTR(f, b) ((f) | ((b) << 4))
+
+#define EFI_BACKGROUND_BLACK 0x00
+#define EFI_BACKGROUND_BLUE 0x10
+#define EFI_BACKGROUND_GREEN 0x20
+#define EFI_BACKGROUND_CYAN (EFI_BACKGROUND_BLUE | EFI_BACKGROUND_GREEN)
+#define EFI_BACKGROUND_RED 0x40
+#define EFI_BACKGROUND_MAGENTA (EFI_BACKGROUND_BLUE | EFI_BACKGROUND_RED)
+#define EFI_BACKGROUND_BROWN (EFI_BACKGROUND_GREEN | EFI_BACKGROUND_RED)
+#define EFI_BACKGROUND_LIGHTGRAY (EFI_BACKGROUND_BLUE | EFI_BACKGROUND_GREEN | EFI_BACKGROUND_RED)
+
+//
+// We currently define attributes from 0 - 7F for color manipulations
+// To internally handle the local display characteristics for a particular character, we are defining
+// Bit 7 to signify the local glyph representation for a character. If turned on, glyphs will be
+// pulled from the wide glyph database and will display locally as a wide character (16 X 19 versus 8 X 19)
+// If bit 7 is off, the narrow glyph database will be used. This does NOT affect information that is sent to
+// non-local displays (e.g. serial or LAN consoles).
+//
+#define EFI_WIDE_ATTRIBUTE 0x80
+
+/**
+ Reset the text output device hardware and optionaly run diagnostics
+
+ @param This Protocol instance pointer.
+ @param ExtendedVerification Driver may perform more exhaustive verfication
+ operation of the device during reset.
+
+ @retval EFI_SUCCESS The text output device was reset.
+ @retval EFI_DEVICE_ERROR The text output device is not functioning correctly and
+ could not be reset.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_TEXT_RESET)(
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ );
+
+/**
+ Write a Unicode string to the output device.
+
+ @param This Protocol instance pointer.
+ @param String The NULL-terminated Unicode string to be displayed on the output
+ device(s). All output devices must also support the Unicode
+ drawing defined in this file.
+
+ @retval EFI_SUCCESS The string was output to the device.
+ @retval EFI_DEVICE_ERROR The device reported an error while attempting to output
+ the text.
+ @retval EFI_UNSUPPORTED The output device's mode is not currently in a
+ defined text mode.
+ @retval EFI_WARN_UNKNOWN_GLYPH This warning code indicates that some of the
+ characters in the Unicode string could not be
+ rendered and were skipped.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_TEXT_STRING)(
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN CHAR16 *String
+ );
+
+/**
+ Verifies that all characters in a Unicode string can be output to the
+ target device.
+
+ @param This Protocol instance pointer.
+ @param String The NULL-terminated Unicode string to be examined for the output
+ device(s).
+
+ @retval EFI_SUCCESS The device(s) are capable of rendering the output string.
+ @retval EFI_UNSUPPORTED Some of the characters in the Unicode string cannot be
+ rendered by one or more of the output devices mapped
+ by the EFI handle.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_TEXT_TEST_STRING)(
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN CHAR16 *String
+ );
+
+/**
+ Returns information for an available text mode that the output device(s)
+ supports.
+
+ @param This Protocol instance pointer.
+ @param ModeNumber The mode number to return information on.
+ @param Columns Returns the geometry of the text output device for the
+ requested ModeNumber.
+ @param Rows Returns the geometry of the text output device for the
+ requested ModeNumber.
+
+ @retval EFI_SUCCESS The requested mode information was returned.
+ @retval EFI_DEVICE_ERROR The device had an error and could not complete the request.
+ @retval EFI_UNSUPPORTED The mode number was not valid.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_TEXT_QUERY_MODE)(
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN UINTN ModeNumber,
+ OUT UINTN *Columns,
+ OUT UINTN *Rows
+ );
+
+/**
+ Sets the output device(s) to a specified mode.
+
+ @param This Protocol instance pointer.
+ @param ModeNumber The mode number to set.
+
+ @retval EFI_SUCCESS The requested text mode was set.
+ @retval EFI_DEVICE_ERROR The device had an error and could not complete the request.
+ @retval EFI_UNSUPPORTED The mode number was not valid.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_TEXT_SET_MODE)(
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN UINTN ModeNumber
+ );
+
+/**
+ Sets the background and foreground colors for the OutputString () and
+ ClearScreen () functions.
+
+ @param This Protocol instance pointer.
+ @param Attribute The attribute to set. Bits 0..3 are the foreground color, and
+ bits 4..6 are the background color. All other bits are undefined
+ and must be zero. The valid Attributes are defined in this file.
+
+ @retval EFI_SUCCESS The attribute was set.
+ @retval EFI_DEVICE_ ERROR The device had an error and could not complete the request.
+ @retval EFI_UNSUPPORTED The attribute requested is not defined.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_TEXT_SET_ATTRIBUTE)(
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN UINTN Attribute
+ );
+
+/**
+ Clears the output device(s) display to the currently selected background
+ color.
+
+ @param This Protocol instance pointer.
+
+ @retval EFI_SUCCESS The operation completed successfully.
+ @retval EFI_DEVICE_ERROR The device had an error and could not complete the request.
+ @retval EFI_UNSUPPORTED The output device is not in a valid text mode.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_TEXT_CLEAR_SCREEN)(
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This
+ );
+
+/**
+ Sets the current coordinates of the cursor position
+
+ @param This Protocol instance pointer.
+ @param Column The position to set the cursor to. Must be greater than or
+ equal to zero and less than the number of columns and rows
+ by QueryMode ().
+ @param Row The position to set the cursor to. Must be greater than or
+ equal to zero and less than the number of columns and rows
+ by QueryMode ().
+
+ @retval EFI_SUCCESS The operation completed successfully.
+ @retval EFI_DEVICE_ERROR The device had an error and could not complete the request.
+ @retval EFI_UNSUPPORTED The output device is not in a valid text mode, or the
+ cursor position is invalid for the current mode.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_TEXT_SET_CURSOR_POSITION)(
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN UINTN Column,
+ IN UINTN Row
+ );
+
+/**
+ Makes the cursor visible or invisible
+
+ @param This Protocol instance pointer.
+ @param Visible If TRUE, the cursor is set to be visible. If FALSE, the cursor is
+ set to be invisible.
+
+ @retval EFI_SUCCESS The operation completed successfully.
+ @retval EFI_DEVICE_ERROR The device had an error and could not complete the
+ request, or the device does not support changing
+ the cursor mode.
+ @retval EFI_UNSUPPORTED The output device is not in a valid text mode.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_TEXT_ENABLE_CURSOR)(
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN BOOLEAN Visible
+ );
+
+/**
+ @par Data Structure Description:
+ Mode Structure pointed to by Simple Text Out protocol.
+
+ @param MaxMode
+ The number of modes supported by QueryMode () and SetMode ().
+
+ @param Mode
+ The text mode of the output device(s).
+
+ @param Attribute
+ The current character output attribute
+
+ @param CursorColumn
+ The cursor's column.
+
+ @param CursorRow
+ The cursor's row.
+
+ @param CursorVisible
+ The cursor is currently visbile or not.
+
+**/
+typedef struct {
+ INT32 MaxMode;
+
+ //
+ // current settings
+ //
+ INT32 Mode;
+ INT32 Attribute;
+ INT32 CursorColumn;
+ INT32 CursorRow;
+ BOOLEAN CursorVisible;
+} EFI_SIMPLE_TEXT_OUTPUT_MODE;
+
+/**
+ @par Protocol Description:
+ The SIMPLE_TEXT_OUTPUT protocol is used to control text-based output devices.
+ It is the minimum required protocol for any handle supplied as the ConsoleOut
+ or StandardError device. In addition, the minimum supported text mode of such
+ devices is at least 80 x 25 characters.
+
+ @param Reset
+ Reset the ConsoleOut device.
+
+ @param OutputString
+ Displays the Unicode string on the device at the current cursor location.
+
+ @param TestString
+ Tests to see if the ConsoleOut device supports this Unicode string.
+
+ @param QueryMode
+ Queries information concerning the output device's supported text mode.
+
+ @param SetMode
+ Sets the current mode of the output device.
+
+ @param SetAttribute
+ Sets the foreground and background color of the text that is output.
+
+ @param ClearScreen
+ Clears the screen with the currently set background color.
+
+ @param SetCursorPosition
+ Sets the current cursor position.
+
+ @param EnableCursor
+ Turns the visibility of the cursor on/off.
+
+ @param Mode
+ Pointer to SIMPLE_TEXT_OUTPUT_MODE data.
+**/
+struct _EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL {
+ EFI_TEXT_RESET Reset;
+
+ EFI_TEXT_STRING OutputString;
+ EFI_TEXT_TEST_STRING TestString;
+
+ EFI_TEXT_QUERY_MODE QueryMode;
+ EFI_TEXT_SET_MODE SetMode;
+ EFI_TEXT_SET_ATTRIBUTE SetAttribute;
+
+ EFI_TEXT_CLEAR_SCREEN ClearScreen;
+ EFI_TEXT_SET_CURSOR_POSITION SetCursorPosition;
+ EFI_TEXT_ENABLE_CURSOR EnableCursor;
+
+ //
+ // Current mode
+ //
+ EFI_SIMPLE_TEXT_OUTPUT_MODE *Mode;
+};
+
+extern EFI_GUID gEfiSimpleTextOutProtocolGuid;
+
+#endif
diff --git a/gpxe/src/include/gpxe/efi/Uefi.h b/gpxe/src/include/gpxe/efi/Uefi.h
new file mode 100644
index 00000000..58ddb11f
--- /dev/null
+++ b/gpxe/src/include/gpxe/efi/Uefi.h
@@ -0,0 +1,27 @@
+/** @file
+
+ Root include file for Mde Package UEFI, UEFI_APPLICATION type modules.
+
+ This is the include file for any module of type UEFI and UEFI_APPLICATION. Uefi modules only use
+ types defined via this include file and can be ported easily to any
+ environment.
+
+Copyright (c) 2006 - 2007, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __PI_UEFI_H__
+#define __PI_UEFI_H__
+
+#include <gpxe/efi/Uefi/UefiBaseType.h>
+#include <gpxe/efi/Uefi/UefiSpec.h>
+
+#endif
+
diff --git a/gpxe/src/include/gpxe/efi/Uefi/UefiBaseType.h b/gpxe/src/include/gpxe/efi/Uefi/UefiBaseType.h
new file mode 100644
index 00000000..1bda8982
--- /dev/null
+++ b/gpxe/src/include/gpxe/efi/Uefi/UefiBaseType.h
@@ -0,0 +1,174 @@
+/** @file
+
+ Defines data types and constants introduced in UEFI.
+
+ Copyright (c) 2006 - 2008, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __UEFI_BASETYPE_H__
+#define __UEFI_BASETYPE_H__
+
+#include <gpxe/efi/Base.h>
+
+///
+/// Basical data type definitions introduced in UEFI.
+///
+typedef GUID EFI_GUID;
+
+///
+/// Function return status for EFI API
+///
+typedef RETURN_STATUS EFI_STATUS;
+typedef VOID *EFI_HANDLE;
+
+typedef VOID *EFI_EVENT;
+
+typedef UINTN EFI_TPL;
+
+
+typedef UINT64 EFI_LBA;
+
+
+typedef UINT16 STRING_REF;
+
+typedef UINT64 EFI_PHYSICAL_ADDRESS;
+typedef UINT64 EFI_VIRTUAL_ADDRESS;
+
+///
+/// EFI Time Abstraction:
+/// Year: 2000 - 20XX
+/// Month: 1 - 12
+/// Day: 1 - 31
+/// Hour: 0 - 23
+/// Minute: 0 - 59
+/// Second: 0 - 59
+/// Nanosecond: 0 - 999,999,999
+/// TimeZone: -1440 to 1440 or 2047
+///
+typedef struct {
+ UINT16 Year;
+ UINT8 Month;
+ UINT8 Day;
+ UINT8 Hour;
+ UINT8 Minute;
+ UINT8 Second;
+ UINT8 Pad1;
+ UINT32 Nanosecond;
+ INT16 TimeZone;
+ UINT8 Daylight;
+ UINT8 Pad2;
+} EFI_TIME;
+
+
+//
+// Networking Definitions
+//
+typedef struct {
+ UINT8 Addr[4];
+} EFI_IPv4_ADDRESS;
+
+typedef struct {
+ UINT8 Addr[16];
+} EFI_IPv6_ADDRESS;
+
+typedef struct {
+ UINT8 Addr[32];
+} EFI_MAC_ADDRESS;
+
+typedef union {
+ UINT32 Addr[4];
+ EFI_IPv4_ADDRESS v4;
+ EFI_IPv6_ADDRESS v6;
+} EFI_IP_ADDRESS;
+
+
+//
+// Enumeration of EFI_STATUS.
+//
+#define EFI_SUCCESS RETURN_SUCCESS
+#define EFI_LOAD_ERROR RETURN_LOAD_ERROR
+#define EFI_INVALID_PARAMETER RETURN_INVALID_PARAMETER
+#define EFI_UNSUPPORTED RETURN_UNSUPPORTED
+#define EFI_BAD_BUFFER_SIZE RETURN_BAD_BUFFER_SIZE
+#define EFI_BUFFER_TOO_SMALL RETURN_BUFFER_TOO_SMALL
+#define EFI_NOT_READY RETURN_NOT_READY
+#define EFI_DEVICE_ERROR RETURN_DEVICE_ERROR
+#define EFI_WRITE_PROTECTED RETURN_WRITE_PROTECTED
+#define EFI_OUT_OF_RESOURCES RETURN_OUT_OF_RESOURCES
+#define EFI_VOLUME_CORRUPTED RETURN_VOLUME_CORRUPTED
+#define EFI_VOLUME_FULL RETURN_VOLUME_FULL
+#define EFI_NO_MEDIA RETURN_NO_MEDIA
+#define EFI_MEDIA_CHANGED RETURN_MEDIA_CHANGED
+#define EFI_NOT_FOUND RETURN_NOT_FOUND
+#define EFI_ACCESS_DENIED RETURN_ACCESS_DENIED
+#define EFI_NO_RESPONSE RETURN_NO_RESPONSE
+#define EFI_NO_MAPPING RETURN_NO_MAPPING
+#define EFI_TIMEOUT RETURN_TIMEOUT
+#define EFI_NOT_STARTED RETURN_NOT_STARTED
+#define EFI_ALREADY_STARTED RETURN_ALREADY_STARTED
+#define EFI_ABORTED RETURN_ABORTED
+#define EFI_ICMP_ERROR RETURN_ICMP_ERROR
+#define EFI_TFTP_ERROR RETURN_TFTP_ERROR
+#define EFI_PROTOCOL_ERROR RETURN_PROTOCOL_ERROR
+#define EFI_INCOMPATIBLE_VERSION RETURN_INCOMPATIBLE_VERSION
+#define EFI_SECURITY_VIOLATION RETURN_SECURITY_VIOLATION
+#define EFI_CRC_ERROR RETURN_CRC_ERROR
+#define EFI_END_OF_MEDIA RETURN_END_OF_MEDIA
+#define EFI_END_OF_FILE RETURN_END_OF_FILE
+#define EFI_INVALID_LANGUAGE RETURN_INVALID_LANGUAGE
+
+#define EFI_WARN_UNKNOWN_GLYPH RETURN_WARN_UNKNOWN_GLYPH
+#define EFI_WARN_DELETE_FAILURE RETURN_WARN_DELETE_FAILURE
+#define EFI_WARN_WRITE_FAILURE RETURN_WARN_WRITE_FAILURE
+#define EFI_WARN_BUFFER_TOO_SMALL RETURN_WARN_BUFFER_TOO_SMALL
+
+
+#define NULL_HANDLE ((VOID *) 0)
+
+//
+// Define macro to encode the status code.
+//
+#define EFIERR(_a) ENCODE_ERROR(_a)
+
+#define EFI_ERROR(A) RETURN_ERROR(A)
+
+//
+// Define macros to build data structure signatures from characters.
+//
+#define EFI_SIGNATURE_16(A, B) ((A) | (B << 8))
+#define EFI_SIGNATURE_32(A, B, C, D) (EFI_SIGNATURE_16 (A, B) | (EFI_SIGNATURE_16 (C, D) << 16))
+#define EFI_SIGNATURE_64(A, B, C, D, E, F, G, H) \
+ (EFI_SIGNATURE_32 (A, B, C, D) | ((UINT64) (EFI_SIGNATURE_32 (E, F, G, H)) << 32))
+
+
+///
+/// Returns the byte offset to a field within a structure
+///
+#define EFI_FIELD_OFFSET(TYPE,Field) ((UINTN)(&(((TYPE *) 0)->Field)))
+
+//
+// The EFI memory allocation functions work in units of EFI_PAGEs that are
+// 4K. This should in no way be confused with the page size of the processor.
+// An EFI_PAGE is just the quanta of memory in EFI.
+//
+#define EFI_PAGE_SIZE 0x1000
+#define EFI_PAGE_MASK 0xFFF
+#define EFI_PAGE_SHIFT 12
+
+#define EFI_SIZE_TO_PAGES(a) (((a) >> EFI_PAGE_SHIFT) + (((a) & EFI_PAGE_MASK) ? 1 : 0))
+
+#define EFI_PAGES_TO_SIZE(a) ( (a) << EFI_PAGE_SHIFT)
+
+
+#define EFI_MAX_BIT MAX_BIT
+#define EFI_MAX_ADDRESS MAX_ADDRESS
+
+#endif
diff --git a/gpxe/src/include/gpxe/efi/Uefi/UefiGpt.h b/gpxe/src/include/gpxe/efi/Uefi/UefiGpt.h
new file mode 100644
index 00000000..70d62fca
--- /dev/null
+++ b/gpxe/src/include/gpxe/efi/Uefi/UefiGpt.h
@@ -0,0 +1,66 @@
+/** @file
+ EFI Guid Partition Table Format Definition.
+
+ Copyright (c) 2006 - 2007, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __UEFI_GPT_H__
+#define __UEFI_GPT_H__
+
+#define PRIMARY_PART_HEADER_LBA 1
+
+///
+/// EFI Partition Table Signature: "EFI PART"
+///
+#define EFI_PTAB_HEADER_ID 0x5452415020494645ULL
+
+#pragma pack(1)
+
+///
+/// GPT Partition Table Header
+///
+typedef struct {
+ EFI_TABLE_HEADER Header;
+ EFI_LBA MyLBA;
+ EFI_LBA AlternateLBA;
+ EFI_LBA FirstUsableLBA;
+ EFI_LBA LastUsableLBA;
+ EFI_GUID DiskGUID;
+ EFI_LBA PartitionEntryLBA;
+ UINT32 NumberOfPartitionEntries;
+ UINT32 SizeOfPartitionEntry;
+ UINT32 PartitionEntryArrayCRC32;
+} EFI_PARTITION_TABLE_HEADER;
+
+///
+/// GPT Partition Entry
+///
+typedef struct {
+ EFI_GUID PartitionTypeGUID;
+ EFI_GUID UniquePartitionGUID;
+ EFI_LBA StartingLBA;
+ EFI_LBA EndingLBA;
+ UINT64 Attributes;
+ CHAR16 PartitionName[36];
+} EFI_PARTITION_ENTRY;
+
+///
+/// GPT Partition Entry Status
+///
+typedef struct {
+ BOOLEAN OutOfRange;
+ BOOLEAN Overlap;
+} EFI_PARTITION_ENTRY_STATUS;
+
+#pragma pack()
+#endif
+
+
diff --git a/gpxe/src/include/gpxe/efi/Uefi/UefiInternalFormRepresentation.h b/gpxe/src/include/gpxe/efi/Uefi/UefiInternalFormRepresentation.h
new file mode 100644
index 00000000..2a25c491
--- /dev/null
+++ b/gpxe/src/include/gpxe/efi/Uefi/UefiInternalFormRepresentation.h
@@ -0,0 +1,1499 @@
+/** @file
+ This file defines the encoding for the VFR (Visual Form Representation) language.
+ IFR is primarily consumed by the EFI presentation engine, and produced by EFI
+ internal application and drivers as well as all add-in card option-ROM drivers
+
+ Copyright (c) 2006 - 2008, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+ @par Revision Reference:
+ These definitions are from UEFI2.1.
+
+**/
+
+#ifndef __UEFI_INTERNAL_FORMREPRESENTATION_H__
+#define __UEFI_INTERNAL_FORMREPRESENTATION_H__
+
+///
+/// The following types are currently defined:
+///
+typedef UINT32 RELOFST;
+
+typedef VOID* EFI_HII_HANDLE;
+typedef CHAR16* EFI_STRING;
+typedef UINT16 EFI_IMAGE_ID;
+typedef UINT16 EFI_QUESTION_ID;
+typedef UINT16 EFI_STRING_ID;
+typedef UINT16 EFI_FORM_ID;
+typedef UINT16 EFI_VARSTORE_ID;
+typedef UINT16 EFI_DEFAULT_ID;
+typedef UINT32 EFI_HII_FONT_STYLE;
+
+
+
+#pragma pack(1)
+
+
+///
+/// HII package list
+///
+typedef struct {
+ EFI_GUID PackageListGuid;
+ UINT32 PackageLength;
+} EFI_HII_PACKAGE_LIST_HEADER;
+
+/**
+
+ Each package starts with a header, as defined above, which
+ indicates the size and type of the package. When added to a
+ pointer pointing to the start of the header, Length points at
+ the next package. The package lists form a package list when
+ concatenated together and terminated with an
+ EFI_HII_PACKAGE_HEADER with a Type of EFI_HII_PACKAGE_END. The
+ type EFI_HII_PACKAGE_TYPE_GUID is used for vendor-defined HII
+ packages, whose contents are determined by the Guid. The range
+ of package types starting with EFI_HII_PACKAGE_TYPE_SYSTEM_BEGIN
+ through EFI_HII_PACKAGE_TYPE_SYSTEM_END are reserved for system
+ firmware implementers.
+
+ @param Length The size of the package in bytes.
+
+ @param Type The package type. See EFI_HII_PACKAGE_TYPE_x,
+ below.
+
+ @param Data The package data, the format of which is
+ determined by Type.
+
+**/
+typedef struct {
+ UINT32 Length:24;
+ UINT32 Type:8;
+ // UINT8 Data[...];
+} EFI_HII_PACKAGE_HEADER;
+
+//
+// EFI_HII_PACKAGE_TYPE_x.
+//
+#define EFI_HII_PACKAGE_TYPE_ALL 0x00
+#define EFI_HII_PACKAGE_TYPE_GUID 0x01
+#define EFI_HII_PACKAGE_FORM 0x02
+#define EFI_HII_PACKAGE_KEYBOARD_LAYOUT 0x03
+#define EFI_HII_PACKAGE_STRINGS 0x04
+#define EFI_HII_PACKAGE_FONTS 0x05
+#define EFI_HII_PACKAGE_IMAGES 0x06
+#define EFI_HII_PACKAGE_SIMPLE_FONTS 0x07
+#define EFI_HII_PACKAGE_DEVICE_PATH 0x08
+#define EFI_HII_PACKAGE_END 0xDF
+#define EFI_HII_PACKAGE_TYPE_SYSTEM_BEGIN 0xE0
+#define EFI_HII_PACKAGE_TYPE_SYSTEM_END 0xFF
+
+//
+// Simplified Font Package
+//
+
+#define EFI_GLYPH_HEIGHT 19
+#define EFI_GLYPH_WIDTH 8
+//
+// Contents of EFI_NARROW_GLYPH.Attributes
+//
+#define EFI_GLYPH_NON_SPACING 0x01
+#define EFI_GLYPH_WIDE 0x02
+
+typedef struct {
+ CHAR16 UnicodeWeight;
+ UINT8 Attributes;
+ UINT8 GlyphCol1[EFI_GLYPH_HEIGHT];
+} EFI_NARROW_GLYPH;
+
+typedef struct {
+ CHAR16 UnicodeWeight;
+ UINT8 Attributes;
+ UINT8 GlyphCol1[EFI_GLYPH_HEIGHT];
+ UINT8 GlyphCol2[EFI_GLYPH_HEIGHT];
+ UINT8 Pad[3];
+} EFI_WIDE_GLYPH;
+
+
+typedef struct _EFI_HII_SIMPLE_FONT_PACKAGE_HDR {
+ EFI_HII_PACKAGE_HEADER Header;
+ UINT16 NumberOfNarrowGlyphs;
+ UINT16 NumberOfWideGlyphs;
+ // EFI_NARROW_GLYPH NarrowGlyphs[];
+ // EFI_WIDE_GLYPH WideGlyphs[];
+} EFI_HII_SIMPLE_FONT_PACKAGE_HDR;
+
+//
+// Font Package
+//
+
+#define EFI_HII_FONT_STYLE_NORMAL 0x00000000
+#define EFI_HII_FONT_STYLE_BOLD 0x00000001
+#define EFI_HII_FONT_STYLE_ITALIC 0x00000002
+#define EFI_HII_FONT_STYLE_EMBOSS 0x00010000
+#define EFI_HII_FONT_STYLE_OUTLINE 0x00020000
+#define EFI_HII_FONT_STYLE_SHADOW 0x00040000
+#define EFI_HII_FONT_STYLE_UNDERLINE 0x00080000
+#define EFI_HII_FONT_STYLE_DBL_UNDER 0x00100000
+
+typedef struct _EFI_HII_GLYPH_INFO {
+ UINT16 Width;
+ UINT16 Height;
+ INT16 OffsetX;
+ INT16 OffsetY;
+ INT16 AdvanceX;
+} EFI_HII_GLYPH_INFO;
+
+typedef struct _EFI_HII_FONT_PACKAGE_HDR {
+ EFI_HII_PACKAGE_HEADER Header;
+ UINT32 HdrSize;
+ UINT32 GlyphBlockOffset;
+ EFI_HII_GLYPH_INFO Cell;
+ EFI_HII_FONT_STYLE FontStyle;
+ CHAR16 FontFamily[1];
+} EFI_HII_FONT_PACKAGE_HDR;
+
+#define EFI_HII_GIBT_END 0x00
+#define EFI_HII_GIBT_GLYPH 0x10
+#define EFI_HII_GIBT_GLYPHS 0x11
+#define EFI_HII_GIBT_GLYPH_DEFAULT 0x12
+#define EFI_HII_GIBT_GLYPHS_DEFAULT 0x13
+#define EFI_HII_GIBT_DUPLICATE 0x20
+#define EFI_HII_GIBT_SKIP2 0x21
+#define EFI_HII_GIBT_SKIP1 0x22
+#define EFI_HII_GIBT_DEFAULTS 0x23
+#define EFI_HII_GIBT_EXT1 0x30
+#define EFI_HII_GIBT_EXT2 0x31
+#define EFI_HII_GIBT_EXT4 0x32
+
+typedef struct _EFI_HII_GLYPH_BLOCK {
+ UINT8 BlockType;
+} EFI_HII_GLYPH_BLOCK;
+
+typedef struct _EFI_HII_GIBT_DEFAULTS_BLOCK {
+ EFI_HII_GLYPH_BLOCK Header;
+ EFI_HII_GLYPH_INFO Cell;
+} EFI_HII_GIBT_DEFAULTS_BLOCK;
+
+typedef struct _EFI_HII_GIBT_DUPLICATE_BLOCK {
+ EFI_HII_GLYPH_BLOCK Header;
+ CHAR16 CharValue;
+} EFI_HII_GIBT_DUPLICATE_BLOCK;
+
+typedef struct _EFI_GLYPH_GIBT_END_BLOCK {
+ EFI_HII_GLYPH_BLOCK Header;
+} EFI_GLYPH_GIBT_END_BLOCK;
+
+typedef struct _EFI_HII_GIBT_EXT1_BLOCK {
+ EFI_HII_GLYPH_BLOCK Header;
+ UINT8 BlockType2;
+ UINT8 Length;
+} EFI_HII_GIBT_EXT1_BLOCK;
+
+typedef struct _EFI_HII_GIBT_EXT2_BLOCK {
+ EFI_HII_GLYPH_BLOCK Header;
+ UINT8 BlockType2;
+ UINT16 Length;
+} EFI_HII_GIBT_EXT2_BLOCK;
+
+typedef struct _EFI_HII_GIBT_EXT4_BLOCK {
+ EFI_HII_GLYPH_BLOCK Header;
+ UINT8 BlockType2;
+ UINT32 Length;
+} EFI_HII_GIBT_EXT4_BLOCK;
+
+typedef struct _EFI_HII_GIBT_GLYPH_BLOCK {
+ EFI_HII_GLYPH_BLOCK Header;
+ EFI_HII_GLYPH_INFO Cell;
+ UINT8 BitmapData[1]; // the number of bytes per bitmap can be calculated by ((Cell.Width+7)/8)*Cell.Height
+} EFI_HII_GIBT_GLYPH_BLOCK;
+
+typedef struct _EFI_HII_GIBT_GLYPHS_BLOCK {
+ EFI_HII_GLYPH_BLOCK Header;
+ EFI_HII_GLYPH_INFO Cell;
+ UINT16 Count;
+ UINT8 BitmapData[1]; // the number of bytes per bitmap can be calculated by ((Cell.Width+7)/8)*Cell.Height
+} EFI_HII_GIBT_GLYPHS_BLOCK;
+
+typedef struct _EFI_HII_GIBT_GLYPH_DEFAULT_BLOCK {
+ EFI_HII_GLYPH_BLOCK Header;
+ UINT8 BitmapData[1]; // the number of bytes per bitmap can be calculated by ((Global.Cell.Width+7)/8)*Global.Cell.Height
+} EFI_HII_GIBT_GLYPH_DEFAULT_BLOCK;
+
+typedef struct _EFI_HII_GIBT_GLYPHS_DEFAULT_BLOCK {
+ EFI_HII_GLYPH_BLOCK Header;
+ UINT16 Count;
+ UINT8 BitmapData[1]; // the number of bytes per bitmap can be calculated by ((Global.Cell.Width+7)/8)*Global.Cell.Height
+} EFI_HII_GIBT_GLYPHS_DEFAULT_BLOCK;
+
+typedef struct _EFI_HII_GIBT_SKIP1_BLOCK {
+ EFI_HII_GLYPH_BLOCK Header;
+ UINT8 SkipCount;
+} EFI_HII_GIBT_SKIP1_BLOCK;
+
+typedef struct _EFI_HII_GIBT_SKIP2_BLOCK {
+ EFI_HII_GLYPH_BLOCK Header;
+ UINT16 SkipCount;
+} EFI_HII_GIBT_SKIP2_BLOCK;
+
+//
+// Device Path Package
+//
+typedef struct _EFI_HII_DEVICE_PATH_PACKAGE {
+ EFI_HII_PACKAGE_HEADER Header;
+ // EFI_DEVICE_PATH_PROTOCOL DevicePath[];
+} EFI_HII_DEVICE_PATH_PACKAGE;
+
+//
+// GUID Package
+//
+typedef struct _EFI_HII_GUID_PACKAGE_HDR {
+ EFI_HII_PACKAGE_HEADER Header;
+ EFI_GUID Guid;
+ // Data per GUID definition may follow
+} EFI_HII_GUID_PACKAGE_HDR;
+
+//
+// String Package
+//
+
+#define UEFI_CONFIG_LANG L"x-UEFI"
+#define UEFI_CONFIG_LANG2 L"x-i-UEFI" // BUGBUG, spec need to be updated.
+
+typedef struct _EFI_HII_STRING_PACKAGE_HDR {
+ EFI_HII_PACKAGE_HEADER Header;
+ UINT32 HdrSize;
+ UINT32 StringInfoOffset;
+ CHAR16 LanguageWindow[16];
+ EFI_STRING_ID LanguageName;
+ CHAR8 Language[1];
+} EFI_HII_STRING_PACKAGE_HDR;
+
+typedef struct {
+ UINT8 BlockType;
+} EFI_HII_STRING_BLOCK;
+
+#define EFI_HII_SIBT_END 0x00
+#define EFI_HII_SIBT_STRING_SCSU 0x10
+#define EFI_HII_SIBT_STRING_SCSU_FONT 0x11
+#define EFI_HII_SIBT_STRINGS_SCSU 0x12
+#define EFI_HII_SIBT_STRINGS_SCSU_FONT 0x13
+#define EFI_HII_SIBT_STRING_UCS2 0x14
+#define EFI_HII_SIBT_STRING_UCS2_FONT 0x15
+#define EFI_HII_SIBT_STRINGS_UCS2 0x16
+#define EFI_HII_SIBT_STRINGS_UCS2_FONT 0x17
+#define EFI_HII_SIBT_DUPLICATE 0x20
+#define EFI_HII_SIBT_SKIP2 0x21
+#define EFI_HII_SIBT_SKIP1 0x22
+#define EFI_HII_SIBT_EXT1 0x30
+#define EFI_HII_SIBT_EXT2 0x31
+#define EFI_HII_SIBT_EXT4 0x32
+#define EFI_HII_SIBT_FONT 0x40
+
+typedef struct _EFI_HII_SIBT_DUPLICATE_BLOCK {
+ EFI_HII_STRING_BLOCK Header;
+ EFI_STRING_ID StringId;
+} EFI_HII_SIBT_DUPLICATE_BLOCK;
+
+typedef struct _EFI_HII_SIBT_END_BLOCK {
+ EFI_HII_STRING_BLOCK Header;
+} EFI_HII_SIBT_END_BLOCK;
+
+typedef struct _EFI_HII_SIBT_EXT1_BLOCK {
+ EFI_HII_STRING_BLOCK Header;
+ UINT8 BlockType2;
+ UINT8 Length;
+} EFI_HII_SIBT_EXT1_BLOCK;
+
+typedef struct _EFI_HII_SIBT_EXT2_BLOCK {
+ EFI_HII_STRING_BLOCK Header;
+ UINT8 BlockType2;
+ UINT16 Length;
+} EFI_HII_SIBT_EXT2_BLOCK;
+
+typedef struct _EFI_HII_SIBT_EXT4_BLOCK {
+ EFI_HII_STRING_BLOCK Header;
+ UINT8 BlockType2;
+ UINT32 Length;
+} EFI_HII_SIBT_EXT4_BLOCK;
+
+typedef struct _EFI_HII_SIBT_FONT_BLOCK {
+ EFI_HII_SIBT_EXT2_BLOCK Header;
+ UINT8 FontId;
+ UINT16 FontSize;
+ EFI_HII_FONT_STYLE FontStyle;
+ CHAR16 FontName[1];
+} EFI_HII_SIBT_FONT_BLOCK;
+
+typedef struct _EFI_HII_SIBT_SKIP1_BLOCK {
+ EFI_HII_STRING_BLOCK Header;
+ UINT8 SkipCount;
+} EFI_HII_SIBT_SKIP1_BLOCK;
+
+typedef struct _EFI_HII_SIBT_SKIP2_BLOCK {
+ EFI_HII_STRING_BLOCK Header;
+ UINT16 SkipCount;
+} EFI_HII_SIBT_SKIP2_BLOCK;
+
+typedef struct _EFI_HII_SIBT_STRING_SCSU_BLOCK {
+ EFI_HII_STRING_BLOCK Header;
+ UINT8 StringText[1];
+} EFI_HII_SIBT_STRING_SCSU_BLOCK;
+
+typedef struct _EFI_HII_SIBT_STRING_SCSU_FONT_BLOCK {
+ EFI_HII_STRING_BLOCK Header;
+ UINT8 FontIdentifier;
+ UINT8 StringText[1];
+} EFI_HII_SIBT_STRING_SCSU_FONT_BLOCK;
+
+typedef struct _EFI_HII_SIBT_STRINGS_SCSU_BLOCK {
+ EFI_HII_STRING_BLOCK Header;
+ UINT16 StringCount;
+ UINT8 StringText[1];
+} EFI_HII_SIBT_STRINGS_SCSU_BLOCK;
+
+typedef struct _EFI_HII_SIBT_STRINGS_SCSU_FONT_BLOCK {
+ EFI_HII_STRING_BLOCK Header;
+ UINT8 FontIdentifier;
+ UINT16 StringCount;
+ UINT8 StringText[1];
+} EFI_HII_SIBT_STRINGS_SCSU_FONT_BLOCK;
+
+typedef struct _EFI_HII_SIBT_STRING_UCS2_BLOCK {
+ EFI_HII_STRING_BLOCK Header;
+ CHAR16 StringText[1];
+} EFI_HII_SIBT_STRING_UCS2_BLOCK;
+
+typedef struct _EFI_HII_SIBT_STRING_UCS2_FONT_BLOCK {
+ EFI_HII_STRING_BLOCK Header;
+ UINT8 FontIdentifier;
+ CHAR16 StringText[1];
+} EFI_HII_SIBT_STRING_UCS2_FONT_BLOCK;
+
+typedef struct _EFI_HII_SIBT_STRINGS_UCS2_BLOCK {
+ EFI_HII_STRING_BLOCK Header;
+ UINT16 StringCount;
+ CHAR16 StringText[1];
+} EFI_HII_SIBT_STRINGS_UCS2_BLOCK;
+
+typedef struct _EFI_HII_SIBT_STRINGS_UCS2_FONT_BLOCK {
+ EFI_HII_STRING_BLOCK Header;
+ UINT8 FontIdentifier;
+ UINT16 StringCount;
+ CHAR16 StringText[1];
+} EFI_HII_SIBT_STRINGS_UCS2_FONT_BLOCK;
+
+//
+// Image Packages
+//
+
+typedef struct _EFI_HII_IMAGE_PACKAGE_HDR {
+ EFI_HII_PACKAGE_HEADER Header;
+ UINT32 ImageInfoOffset;
+ UINT32 PaletteInfoOffset;
+} EFI_HII_IMAGE_PACKAGE_HDR;
+
+typedef struct _EFI_HII_IMAGE_BLOCK {
+ UINT8 BlockType;
+} EFI_HII_IMAGE_BLOCK;
+
+#define EFI_HII_IIBT_END 0x00
+#define EFI_HII_IIBT_IMAGE_1BIT 0x10
+#define EFI_HII_IIBT_IMAGE_1BIT_TRANS 0x11
+#define EFI_HII_IIBT_IMAGE_4BIT 0x12
+#define EFI_HII_IIBT_IMAGE_4BIT_TRANS 0x13
+#define EFI_HII_IIBT_IMAGE_8BIT 0x14
+#define EFI_HII_IIBT_IMAGE_8BIT_TRANS 0x15
+#define EFI_HII_IIBT_IMAGE_24BIT 0x16
+#define EFI_HII_IIBT_IMAGE_24BIT_TRANS 0x17
+#define EFI_HII_IIBT_IMAGE_JPEG 0x18
+#define EFI_HII_IIBT_DUPLICATE 0x20
+#define EFI_HII_IIBT_SKIP2 0x21
+#define EFI_HII_IIBT_SKIP1 0x22
+#define EFI_HII_IIBT_EXT1 0x30
+#define EFI_HII_IIBT_EXT2 0x31
+#define EFI_HII_IIBT_EXT4 0x32
+
+typedef struct _EFI_HII_IIBT_END_BLOCK {
+ EFI_HII_IMAGE_BLOCK Header;
+} EFI_HII_IIBT_END_BLOCK;
+
+typedef struct _EFI_HII_IIBT_EXT1_BLOCK {
+ EFI_HII_IMAGE_BLOCK Header;
+ UINT8 BlockType2;
+ UINT8 Length;
+} EFI_HII_IIBT_EXT1_BLOCK;
+
+typedef struct _EFI_HII_IIBT_EXT2_BLOCK {
+ EFI_HII_IMAGE_BLOCK Header;
+ UINT8 BlockType2;
+ UINT16 Length;
+} EFI_HII_IIBT_EXT2_BLOCK;
+
+typedef struct _EFI_HII_IIBT_EXT4_BLOCK {
+ EFI_HII_IMAGE_BLOCK Header;
+ UINT8 BlockType2;
+ UINT32 Length;
+} EFI_HII_IIBT_EXT4_BLOCK;
+
+typedef struct _EFI_HII_IIBT_IMAGE_1BIT_BASE {
+ UINT16 Width;
+ UINT16 Height;
+ UINT8 Data[1];
+} EFI_HII_IIBT_IMAGE_1BIT_BASE;
+
+typedef struct _EFI_HII_IIBT_IMAGE_1BIT_BLOCK {
+ EFI_HII_IMAGE_BLOCK Header;
+ UINT8 PaletteIndex;
+ EFI_HII_IIBT_IMAGE_1BIT_BASE Bitmap;
+} EFI_HII_IIBT_IMAGE_1BIT_BLOCK;
+
+typedef struct _EFI_HII_IIBT_IMAGE_1BIT_TRANS_BLOCK {
+ EFI_HII_IMAGE_BLOCK Header;
+ UINT8 PaletteIndex;
+ EFI_HII_IIBT_IMAGE_1BIT_BASE Bitmap;
+} EFI_HII_IIBT_IMAGE_1BIT_TRANS_BLOCK;
+
+typedef struct _EFI_HII_RGB_PIXEL {
+ UINT8 b;
+ UINT8 g;
+ UINT8 r;
+} EFI_HII_RGB_PIXEL;
+
+typedef struct _EFI_HII_IIBT_IMAGE_24BIT_BASE {
+ UINT16 Width;
+ UINT16 Height;
+ EFI_HII_RGB_PIXEL Bitmap[1];
+} EFI_HII_IIBT_IMAGE_24BIT_BASE;
+
+typedef struct _EFI_HII_IIBT_IMAGE_24BIT_BLOCK {
+ EFI_HII_IMAGE_BLOCK Header;
+ EFI_HII_IIBT_IMAGE_24BIT_BASE Bitmap;
+} EFI_HII_IIBT_IMAGE_24BIT_BLOCK;
+
+typedef struct _EFI_HII_IIBT_IMAGE_24BIT_TRANS_BLOCK {
+ EFI_HII_IMAGE_BLOCK Header;
+ EFI_HII_IIBT_IMAGE_24BIT_BASE Bitmap;
+} EFI_HII_IIBT_IMAGE_24BIT_TRANS_BLOCK;
+
+typedef struct _EFI_HII_IIBT_IMAGE_4BIT_BASE {
+ UINT16 Width;
+ UINT16 Height;
+ UINT8 Data[1];
+} EFI_HII_IIBT_IMAGE_4BIT_BASE;
+
+typedef struct _EFI_HII_IIBT_IMAGE_4BIT_BLOCK {
+ EFI_HII_IMAGE_BLOCK Header;
+ UINT8 PaletteIndex;
+ EFI_HII_IIBT_IMAGE_4BIT_BASE Bitmap;
+} EFI_HII_IIBT_IMAGE_4BIT_BLOCK;
+
+typedef struct _EFI_HII_IIBT_IMAGE_4BIT_TRANS_BLOCK {
+ EFI_HII_IMAGE_BLOCK Header;
+ UINT8 PaletteIndex;
+ EFI_HII_IIBT_IMAGE_4BIT_BASE Bitmap;
+} EFI_HII_IIBT_IMAGE_4BIT_TRANS_BLOCK;
+
+typedef struct _EFI_HII_IIBT_IMAGE_8BIT_BASE {
+ UINT16 Width;
+ UINT16 Height;
+ UINT8 Data[1];
+} EFI_HII_IIBT_IMAGE_8BIT_BASE;
+
+typedef struct _EFI_HII_IIBT_IMAGE_8BIT_PALETTE_BLOCK {
+ EFI_HII_IMAGE_BLOCK Header;
+ UINT8 PaletteIndex;
+ EFI_HII_IIBT_IMAGE_8BIT_BASE Bitmap;
+} EFI_HII_IIBT_IMAGE_8BIT_BLOCK;
+
+typedef struct _EFI_HII_IIBT_IMAGE_8BIT_TRANS_BLOCK {
+ EFI_HII_IMAGE_BLOCK Header;
+ UINT8 PaletteIndex;
+ EFI_HII_IIBT_IMAGE_8BIT_BASE Bitmap;
+} EFI_HII_IIBT_IMAGE_8BIT_TRAN_BLOCK;
+
+typedef struct _EFI_HII_IIBT_DUPLICATE_BLOCK {
+ EFI_HII_IMAGE_BLOCK Header;
+ EFI_IMAGE_ID ImageId;
+} EFI_HII_IIBT_DUPLICATE_BLOCK;
+
+typedef struct _EFI_HII_IIBT_JPEG_BLOCK {
+ EFI_HII_IMAGE_BLOCK Header;
+ UINT32 Size;
+ UINT8 Data[1];
+} EFI_HII_IIBT_JPEG_BLOCK;
+
+typedef struct _EFI_HII_IIBT_SKIP1_BLOCK {
+ EFI_HII_IMAGE_BLOCK Header;
+ UINT8 SkipCount;
+} EFI_HII_IIBT_SKIP1_BLOCK;
+
+typedef struct _EFI_HII_IIBT_SKIP2_BLOCK {
+ EFI_HII_IMAGE_BLOCK Header;
+ UINT16 SkipCount;
+} EFI_HII_IIBT_SKIP2_BLOCK;
+
+typedef struct _EFI_HII_IMAGE_PALETTE_INFO_HEADER {
+ UINT16 PaletteCount;
+} EFI_HII_IMAGE_PALETTE_INFO_HEADER;
+
+typedef struct _EFI_HII_IMAGE_PALETTE_INFO {
+ UINT16 PaletteSize;
+ EFI_HII_RGB_PIXEL PaletteValue[1];
+} EFI_HII_IMAGE_PALETTE_INFO;
+
+//
+// Forms Package
+//
+
+typedef struct _EFI_HII_FORM_PACKAGE {
+ EFI_HII_PACKAGE_HEADER Header;
+ // EFI_IFR_OP_HEADER OpCodeHeader;
+ // More op-codes follow
+} EFI_HII_FORM_PACKAGE;
+
+typedef struct {
+ UINT8 Hour;
+ UINT8 Minute;
+ UINT8 Second;
+} EFI_HII_TIME;
+
+typedef struct {
+ UINT16 Year;
+ UINT8 Month;
+ UINT8 Day;
+} EFI_HII_DATE;
+
+typedef union {
+ UINT8 u8;
+ UINT16 u16;
+ UINT32 u32;
+ UINT64 u64;
+ BOOLEAN b;
+ EFI_HII_TIME time;
+ EFI_HII_DATE date;
+ EFI_STRING_ID string;
+} EFI_IFR_TYPE_VALUE;
+
+//
+// IFR Opcodes
+//
+#define EFI_IFR_FORM_OP 0x01
+#define EFI_IFR_SUBTITLE_OP 0x02
+#define EFI_IFR_TEXT_OP 0x03
+#define EFI_IFR_IMAGE_OP 0x04
+#define EFI_IFR_ONE_OF_OP 0x05
+#define EFI_IFR_CHECKBOX_OP 0x06
+#define EFI_IFR_NUMERIC_OP 0x07
+#define EFI_IFR_PASSWORD_OP 0x08
+#define EFI_IFR_ONE_OF_OPTION_OP 0x09
+#define EFI_IFR_SUPPRESS_IF_OP 0x0A
+#define EFI_IFR_LOCKED_OP 0x0B
+#define EFI_IFR_ACTION_OP 0x0C
+#define EFI_IFR_RESET_BUTTON_OP 0x0D
+#define EFI_IFR_FORM_SET_OP 0x0E
+#define EFI_IFR_REF_OP 0x0F
+#define EFI_IFR_NO_SUBMIT_IF_OP 0x10
+#define EFI_IFR_INCONSISTENT_IF_OP 0x11
+#define EFI_IFR_EQ_ID_VAL_OP 0x12
+#define EFI_IFR_EQ_ID_ID_OP 0x13
+#define EFI_IFR_EQ_ID_LIST_OP 0x14
+#define EFI_IFR_AND_OP 0x15
+#define EFI_IFR_OR_OP 0x16
+#define EFI_IFR_NOT_OP 0x17
+#define EFI_IFR_RULE_OP 0x18
+#define EFI_IFR_GRAY_OUT_IF_OP 0x19
+#define EFI_IFR_DATE_OP 0x1A
+#define EFI_IFR_TIME_OP 0x1B
+#define EFI_IFR_STRING_OP 0x1C
+#define EFI_IFR_REFRESH_OP 0x1D
+#define EFI_IFR_DISABLE_IF_OP 0x1E
+#define EFI_IFR_TO_LOWER_OP 0x20
+#define EFI_IFR_TO_UPPER_OP 0x21
+#define EFI_IFR_ORDERED_LIST_OP 0x23
+#define EFI_IFR_VARSTORE_OP 0x24
+#define EFI_IFR_VARSTORE_NAME_VALUE_OP 0x25
+#define EFI_IFR_VARSTORE_EFI_OP 0x26
+#define EFI_IFR_VARSTORE_DEVICE_OP 0x27
+#define EFI_IFR_VERSION_OP 0x28
+#define EFI_IFR_END_OP 0x29
+#define EFI_IFR_MATCH_OP 0x2A
+#define EFI_IFR_EQUAL_OP 0x2F
+#define EFI_IFR_NOT_EQUAL_OP 0x30
+#define EFI_IFR_GREATER_THAN_OP 0x31
+#define EFI_IFR_GREATER_EQUAL_OP 0x32
+#define EFI_IFR_LESS_THAN_OP 0x33
+#define EFI_IFR_LESS_EQUAL_OP 0x34
+#define EFI_IFR_BITWISE_AND_OP 0x35
+#define EFI_IFR_BITWISE_OR_OP 0x36
+#define EFI_IFR_BITWISE_NOT_OP 0x37
+#define EFI_IFR_SHIFT_LEFT_OP 0x38
+#define EFI_IFR_SHIFT_RIGHT_OP 0x39
+#define EFI_IFR_ADD_OP 0x3A
+#define EFI_IFR_SUBTRACT_OP 0x3B
+#define EFI_IFR_MULTIPLY_OP 0x3C
+#define EFI_IFR_DIVIDE_OP 0x3D
+#define EFI_IFR_MODULO_OP 0x3E
+#define EFI_IFR_RULE_REF_OP 0x3F
+#define EFI_IFR_QUESTION_REF1_OP 0x40
+#define EFI_IFR_QUESTION_REF2_OP 0x41
+#define EFI_IFR_UINT8_OP 0x42
+#define EFI_IFR_UINT16_OP 0x43
+#define EFI_IFR_UINT32_OP 0x44
+#define EFI_IFR_UINT64_OP 0x45
+#define EFI_IFR_TRUE_OP 0x46
+#define EFI_IFR_FALSE_OP 0x47
+#define EFI_IFR_TO_UINT_OP 0x48
+#define EFI_IFR_TO_STRING_OP 0x49
+#define EFI_IFR_TO_BOOLEAN_OP 0x4A
+#define EFI_IFR_MID_OP 0x4B
+#define EFI_IFR_FIND_OP 0x4C
+#define EFI_IFR_TOKEN_OP 0x4D
+#define EFI_IFR_STRING_REF1_OP 0x4E
+#define EFI_IFR_STRING_REF2_OP 0x4F
+#define EFI_IFR_CONDITIONAL_OP 0x50
+#define EFI_IFR_QUESTION_REF3_OP 0x51
+#define EFI_IFR_ZERO_OP 0x52
+#define EFI_IFR_ONE_OP 0x53
+#define EFI_IFR_ONES_OP 0x54
+#define EFI_IFR_UNDEFINED_OP 0x55
+#define EFI_IFR_LENGTH_OP 0x56
+#define EFI_IFR_DUP_OP 0x57
+#define EFI_IFR_THIS_OP 0x58
+#define EFI_IFR_SPAN_OP 0x59
+#define EFI_IFR_VALUE_OP 0x5A
+#define EFI_IFR_DEFAULT_OP 0x5B
+#define EFI_IFR_DEFAULTSTORE_OP 0x5C
+#define EFI_IFR_CATENATE_OP 0x5E
+#define EFI_IFR_GUID_OP 0x5F
+
+
+typedef struct _EFI_IFR_OP_HEADER {
+ UINT8 OpCode;
+ UINT8 Length:7;
+ UINT8 Scope:1;
+} EFI_IFR_OP_HEADER;
+
+typedef struct _EFI_IFR_STATEMENT_HEADER {
+ EFI_STRING_ID Prompt;
+ EFI_STRING_ID Help;
+} EFI_IFR_STATEMENT_HEADER;
+
+typedef struct _EFI_IFR_QUESTION_HEADER {
+ EFI_IFR_STATEMENT_HEADER Header;
+ EFI_QUESTION_ID QuestionId;
+ EFI_VARSTORE_ID VarStoreId;
+ union {
+ EFI_STRING_ID VarName;
+ UINT16 VarOffset;
+ } VarStoreInfo;
+ UINT8 Flags;
+} EFI_IFR_QUESTION_HEADER;
+
+#define EFI_IFR_FLAG_READ_ONLY 0x01
+#define EFI_IFR_FLAG_CALLBACK 0x04
+#define EFI_IFR_FLAG_RESET_REQUIRED 0x10
+#define EFI_IFR_FLAG_OPTIONS_ONLY 0x80
+
+typedef struct _EFI_IFR_DEFAULTSTORE {
+ EFI_IFR_OP_HEADER Header;
+ EFI_STRING_ID DefaultName;
+ UINT16 DefaultId;
+} EFI_IFR_DEFAULTSTORE;
+
+#define EFI_HII_DEFAULT_CLASS_STANDARD 0x0000
+#define EFI_HII_DEFAULT_CLASS_MANUFACTURING 0x0001
+#define EFI_HII_DEFAULT_CLASS_SAFE 0x0002
+#define EFI_HII_DEFAULT_CLASS_PLATFORM_BEGIN 0x4000
+#define EFI_HII_DEFAULT_CLASS_PLATFORM_END 0x7fff
+#define EFI_HII_DEFAULT_CLASS_HARDWARE_BEGIN 0x8000
+#define EFI_HII_DEFAULT_CLASS_HARDWARE_END 0xbfff
+#define EFI_HII_DEFAULT_CLASS_FIRMWARE_BEGIN 0xc000
+#define EFI_HII_DEFAULT_CLASS_FIRMWARE_END 0xffff
+
+typedef struct _EFI_IFR_VARSTORE {
+ EFI_IFR_OP_HEADER Header;
+ EFI_GUID Guid;
+ EFI_VARSTORE_ID VarStoreId;
+ UINT16 Size;
+ UINT8 Name[1];
+} EFI_IFR_VARSTORE;
+
+typedef struct _EFI_IFR_VARSTORE_EFI {
+ EFI_IFR_OP_HEADER Header;
+ EFI_VARSTORE_ID VarStoreId;
+ EFI_GUID Guid;
+ UINT32 Attributes;
+} EFI_IFR_VARSTORE_EFI;
+
+typedef struct _EFI_IFR_VARSTORE_NAME_VALUE {
+ EFI_IFR_OP_HEADER Header;
+ EFI_VARSTORE_ID VarStoreId;
+ EFI_GUID Guid;
+} EFI_IFR_VARSTORE_NAME_VALUE;
+
+typedef struct _EFI_IFR_FORM_SET {
+ EFI_IFR_OP_HEADER Header;
+ EFI_GUID Guid;
+ EFI_STRING_ID FormSetTitle;
+ EFI_STRING_ID Help;
+} EFI_IFR_FORM_SET;
+
+typedef struct _EFI_IFR_END {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_END;
+
+typedef struct _EFI_IFR_FORM {
+ EFI_IFR_OP_HEADER Header;
+ UINT16 FormId;
+ EFI_STRING_ID FormTitle;
+} EFI_IFR_FORM;
+
+typedef struct _EFI_IFR_IMAGE {
+ EFI_IFR_OP_HEADER Header;
+ EFI_IMAGE_ID Id;
+} EFI_IFR_IMAGE;
+
+typedef struct _EFI_IFR_LOCKED {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_LOCKED;
+
+typedef struct _EFI_IFR_RULE {
+ EFI_IFR_OP_HEADER Header;
+ UINT8 RuleId;
+} EFI_IFR_RULE;
+
+typedef struct _EFI_IFR_DEFAULT {
+ EFI_IFR_OP_HEADER Header;
+ UINT16 DefaultId;
+ UINT8 Type;
+ EFI_IFR_TYPE_VALUE Value;
+} EFI_IFR_DEFAULT;
+
+typedef struct _EFI_IFR_VALUE {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_VALUE;
+
+typedef struct _EFI_IFR_SUBTITLE {
+ EFI_IFR_OP_HEADER Header;
+ EFI_IFR_STATEMENT_HEADER Statement;
+ UINT8 Flags;
+} EFI_IFR_SUBTITLE;
+
+#define EFI_IFR_FLAGS_HORIZONTAL 0x01
+
+typedef struct _EFI_IFR_CHECKBOX {
+ EFI_IFR_OP_HEADER Header;
+ EFI_IFR_QUESTION_HEADER Question;
+ UINT8 Flags;
+} EFI_IFR_CHECKBOX;
+
+#define EFI_IFR_CHECKBOX_DEFAULT 0x01
+#define EFI_IFR_CHECKBOX_DEFAULT_MFG 0x02
+
+typedef struct _EFI_IFR_TEXT {
+ EFI_IFR_OP_HEADER Header;
+ EFI_IFR_STATEMENT_HEADER Statement;
+ EFI_STRING_ID TextTwo;
+} EFI_IFR_TEXT;
+
+typedef struct _EFI_IFR_REF {
+ EFI_IFR_OP_HEADER Header;
+ EFI_IFR_QUESTION_HEADER Question;
+ EFI_FORM_ID FormId;
+} EFI_IFR_REF;
+
+typedef struct _EFI_IFR_REF2 {
+ EFI_IFR_OP_HEADER Header;
+ EFI_IFR_QUESTION_HEADER Question;
+ EFI_FORM_ID FormId;
+ EFI_QUESTION_ID QuestionId;
+} EFI_IFR_REF2;
+
+typedef struct _EFI_IFR_REF3 {
+ EFI_IFR_OP_HEADER Header;
+ EFI_IFR_QUESTION_HEADER Question;
+ EFI_FORM_ID FormId;
+ EFI_QUESTION_ID QuestionId;
+ EFI_GUID FormSetId;
+} EFI_IFR_REF3;
+
+typedef struct _EFI_IFR_REF4 {
+ EFI_IFR_OP_HEADER Header;
+ EFI_IFR_QUESTION_HEADER Question;
+ EFI_FORM_ID FormId;
+ EFI_QUESTION_ID QuestionId;
+ EFI_GUID FormSetId;
+ EFI_STRING_ID DevicePath;
+} EFI_IFR_REF4;
+
+typedef struct _EFI_IFR_RESET_BUTTON {
+ EFI_IFR_OP_HEADER Header;
+ EFI_IFR_QUESTION_HEADER Question;
+ EFI_DEFAULT_ID DefaultId;
+} EFI_IFR_RESET_BUTTON;
+
+typedef struct _EFI_IFR_ACTION {
+ EFI_IFR_OP_HEADER Header;
+ EFI_IFR_QUESTION_HEADER Question;
+ EFI_STRING_ID QuestionConfig;
+} EFI_IFR_ACTION;
+
+typedef struct _EFI_IFR_ACTION_1 {
+ EFI_IFR_OP_HEADER Header;
+ EFI_IFR_QUESTION_HEADER Question;
+} EFI_IFR_ACTION_1;
+
+typedef struct _EFI_IFR_DATE {
+ EFI_IFR_OP_HEADER Header;
+ EFI_IFR_QUESTION_HEADER Question;
+ UINT8 Flags;
+} EFI_IFR_DATE;
+
+#define EFI_QF_DATE_YEAR_SUPPRESS 0x01
+#define EFI_QF_DATE_MONTH_SUPPRESS 0x02
+#define EFI_QF_DATE_DAY_SUPPRESS 0x04
+
+#define EFI_QF_DATE_STORAGE 0x30
+#define QF_DATE_STORAGE_NORMAL 0x00
+#define QF_DATE_STORAGE_TIME 0x10
+#define QF_DATE_STORAGE_WAKEUP 0x20
+
+typedef union {
+ struct {
+ UINT8 MinValue;
+ UINT8 MaxValue;
+ UINT8 Step;
+ } u8;
+ struct {
+ UINT16 MinValue;
+ UINT16 MaxValue;
+ UINT16 Step;
+ } u16;
+ struct {
+ UINT32 MinValue;
+ UINT32 MaxValue;
+ UINT32 Step;
+ } u32;
+ struct {
+ UINT64 MinValue;
+ UINT64 MaxValue;
+ UINT64 Step;
+ } u64;
+} MINMAXSTEP_DATA;
+
+typedef struct _EFI_IFR_NUMERIC {
+ EFI_IFR_OP_HEADER Header;
+ EFI_IFR_QUESTION_HEADER Question;
+ UINT8 Flags;
+ MINMAXSTEP_DATA data;
+} EFI_IFR_NUMERIC;
+
+#define EFI_IFR_NUMERIC_SIZE 0x03
+#define EFI_IFR_NUMERIC_SIZE_1 0x00
+#define EFI_IFR_NUMERIC_SIZE_2 0x01
+#define EFI_IFR_NUMERIC_SIZE_4 0x02
+#define EFI_IFR_NUMERIC_SIZE_8 0x03
+
+#define EFI_IFR_DISPLAY 0x30
+#define EFI_IFR_DISPLAY_INT_DEC 0x00
+#define EFI_IFR_DISPLAY_UINT_DEC 0x10
+#define EFI_IFR_DISPLAY_UINT_HEX 0x20
+
+typedef struct _EFI_IFR_ONE_OF {
+ EFI_IFR_OP_HEADER Header;
+ EFI_IFR_QUESTION_HEADER Question;
+ UINT8 Flags;
+ MINMAXSTEP_DATA data;
+} EFI_IFR_ONE_OF;
+
+typedef struct _EFI_IFR_STRING {
+ EFI_IFR_OP_HEADER Header;
+ EFI_IFR_QUESTION_HEADER Question;
+ UINT8 MinSize;
+ UINT8 MaxSize;
+ UINT8 Flags;
+} EFI_IFR_STRING;
+
+#define EFI_IFR_STRING_MULTI_LINE 0x01
+
+typedef struct _EFI_IFR_PASSWORD {
+ EFI_IFR_OP_HEADER Header;
+ EFI_IFR_QUESTION_HEADER Question;
+ UINT16 MinSize;
+ UINT16 MaxSize;
+} EFI_IFR_PASSWORD;
+
+typedef struct _EFI_IFR_ORDERED_LIST {
+ EFI_IFR_OP_HEADER Header;
+ EFI_IFR_QUESTION_HEADER Question;
+ UINT8 MaxContainers;
+ UINT8 Flags;
+} EFI_IFR_ORDERED_LIST;
+
+#define EFI_IFR_UNIQUE_SET 0x01
+#define EFI_IFR_NO_EMPTY_SET 0x02
+
+typedef struct _EFI_IFR_TIME {
+ EFI_IFR_OP_HEADER Header;
+ EFI_IFR_QUESTION_HEADER Question;
+ UINT8 Flags;
+} EFI_IFR_TIME;
+
+#define QF_TIME_HOUR_SUPPRESS 0x01
+#define QF_TIME_MINUTE_SUPPRESS 0x02
+#define QF_TIME_SECOND_SUPPRESS 0x04
+
+#define QF_TIME_STORAGE 0x30
+#define QF_TIME_STORAGE_NORMAL 0x00
+#define QF_TIME_STORAGE_TIME 0x10
+#define QF_TIME_STORAGE_WAKEUP 0x20
+
+typedef struct _EFI_IFR_DISABLE_IF {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_DISABLE_IF;
+
+typedef struct _EFI_IFR_SUPPRESS_IF {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_SUPPRESS_IF;
+
+typedef struct _EFI_IFR_GRAY_OUT_IF {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_GRAY_OUT_IF;
+
+typedef struct _EFI_IFR_INCONSISTENT_IF {
+ EFI_IFR_OP_HEADER Header;
+ EFI_STRING_ID Error;
+} EFI_IFR_INCONSISTENT_IF;
+
+typedef struct _EFI_IFR_NO_SUBMIT_IF {
+ EFI_IFR_OP_HEADER Header;
+ EFI_STRING_ID Error;
+} EFI_IFR_NO_SUBMIT_IF;
+
+typedef struct _EFI_IFR_REFRESH {
+ EFI_IFR_OP_HEADER Header;
+ UINT8 RefreshInterval;
+} EFI_IFR_REFRESH;
+
+typedef struct _EFI_IFR_VARSTORE_DEVICE {
+ EFI_IFR_OP_HEADER Header;
+ EFI_STRING_ID DevicePath;
+} EFI_IFR_VARSTORE_DEVICE;
+
+typedef struct _EFI_IFR_ONE_OF_OPTION {
+ EFI_IFR_OP_HEADER Header;
+ EFI_STRING_ID Option;
+ UINT8 Flags;
+ UINT8 Type;
+ EFI_IFR_TYPE_VALUE Value;
+} EFI_IFR_ONE_OF_OPTION;
+
+#define EFI_IFR_TYPE_NUM_SIZE_8 0x00
+#define EFI_IFR_TYPE_NUM_SIZE_16 0x01
+#define EFI_IFR_TYPE_NUM_SIZE_32 0x02
+#define EFI_IFR_TYPE_NUM_SIZE_64 0x03
+#define EFI_IFR_TYPE_BOOLEAN 0x04
+#define EFI_IFR_TYPE_TIME 0x05
+#define EFI_IFR_TYPE_DATE 0x06
+#define EFI_IFR_TYPE_STRING 0x07
+#define EFI_IFR_TYPE_OTHER 0x08
+
+#define EFI_IFR_OPTION_DEFAULT 0x10
+#define EFI_IFR_OPTION_DEFAULT_MFG 0x20
+
+typedef struct _EFI_IFR_GUID {
+ EFI_IFR_OP_HEADER Header;
+ EFI_GUID Guid;
+ //Optional Data Follows
+} EFI_IFR_GUID;
+
+typedef struct _EFI_IFR_DUP {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_DUP;
+
+typedef struct _EFI_IFR_EQ_ID_ID {
+ EFI_IFR_OP_HEADER Header;
+ EFI_QUESTION_ID QuestionId1;
+ EFI_QUESTION_ID QuestionId2;
+} EFI_IFR_EQ_ID_ID;
+
+typedef struct _EFI_IFR_EQ_ID_VAL {
+ EFI_IFR_OP_HEADER Header;
+ EFI_QUESTION_ID QuestionId;
+ UINT16 Value;
+} EFI_IFR_EQ_ID_VAL;
+
+typedef struct _EFI_IFR_EQ_ID_LIST {
+ EFI_IFR_OP_HEADER Header;
+ EFI_QUESTION_ID QuestionId;
+ UINT16 ListLength;
+ UINT16 ValueList[1];
+} EFI_IFR_EQ_ID_LIST;
+
+typedef struct _EFI_IFR_QUESTION_REF1 {
+ EFI_IFR_OP_HEADER Header;
+ EFI_QUESTION_ID QuestionId;
+} EFI_IFR_QUESTION_REF1;
+
+typedef struct _EFI_IFR_UINT8 {
+ EFI_IFR_OP_HEADER Header;
+ UINT8 Value;
+} EFI_IFR_UINT8;
+
+typedef struct _EFI_IFR_UINT16 {
+ EFI_IFR_OP_HEADER Header;
+ UINT16 Value;
+} EFI_IFR_UINT16;
+
+typedef struct _EFI_IFR_QUESTION_REF2 {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_QUESTION_REF2;
+
+typedef struct _EFI_IFR_UINT32 {
+ EFI_IFR_OP_HEADER Header;
+ UINT32 Value;
+} EFI_IFR_UINT32;
+
+typedef struct _EFI_IFR_UINT64 {
+ EFI_IFR_OP_HEADER Header;
+ UINT64 Value;
+} EFI_IFR_UINT64;
+
+typedef struct _EFI_IFR_QUESTION_REF3 {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_QUESTION_REF3;
+
+typedef struct _EFI_IFR_QUESTION_REF3_2 {
+ EFI_IFR_OP_HEADER Header;
+ EFI_STRING_ID DevicePath;
+} EFI_IFR_QUESTION_REF3_2;
+
+typedef struct _EFI_IFR_QUESTION_REF3_3 {
+ EFI_IFR_OP_HEADER Header;
+ EFI_STRING_ID DevicePath;
+ EFI_GUID Guid;
+} EFI_IFR_QUESTION_REF3_3;
+
+typedef struct _EFI_IFR_RULE_REF {
+ EFI_IFR_OP_HEADER Header;
+ UINT8 RuleId;
+} EFI_IFR_RULE_REF;
+
+typedef struct _EFI_IFR_STRING_REF1 {
+ EFI_IFR_OP_HEADER Header;
+ EFI_STRING_ID StringId;
+} EFI_IFR_STRING_REF1;
+
+typedef struct _EFI_IFR_STRING_REF2 {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_STRING_REF2;
+
+typedef struct _EFI_IFR_THIS {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_THIS;
+
+typedef struct _EFI_IFR_TRUE {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_TRUE;
+
+typedef struct _EFI_IFR_FALSE {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_FALSE;
+
+typedef struct _EFI_IFR_ONE {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_ONE;
+
+typedef struct _EFI_IFR_ONES {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_ONES;
+
+typedef struct _EFI_IFR_ZERO {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_ZERO;
+
+typedef struct _EFI_IFR_UNDEFINED {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_UNDEFINED;
+
+typedef struct _EFI_IFR_VERSION {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_VERSION;
+
+typedef struct _EFI_IFR_LENGTH {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_LENGTH;
+
+typedef struct _EFI_IFR_NOT {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_NOT;
+
+typedef struct _EFI_IFR_BITWISE_NOT {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_BITWISE_NOT;
+
+typedef struct _EFI_IFR_TO_BOOLEAN {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_TO_BOOLEAN;
+
+#define EFI_IFR_STRING_UNSIGNED_DEC 0
+#define EFI_IFR_STRING_SIGNED_DEC 1
+#define EFI_IFR_STRING_LOWERCASE_HEX 2
+#define EFI_IFR_STRING_UPPERCASE_HEX 3
+
+#define EFI_IFR_STRING_ASCII 0
+#define EFI_IFR_STRING_UNICODE 8
+
+typedef struct _EFI_IFR_TO_STRING {
+ EFI_IFR_OP_HEADER Header;
+ UINT8 Format;
+} EFI_IFR_TO_STRING;
+
+typedef struct _EFI_IFR_TO_UINT {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_TO_UINT;
+
+typedef struct _EFI_IFR_TO_UPPER {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_TO_UPPER;
+
+typedef struct _EFI_IFR_TO_LOWER {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_TO_LOWER;
+
+typedef struct _EFI_IFR_ADD {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_ADD;
+
+typedef struct _EFI_IFR_AND {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_AND;
+
+typedef struct _EFI_IFR_BITWISE_AND {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_BITWISE_AND;
+
+typedef struct _EFI_IFR_BITWISE_OR {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_BITWISE_OR;
+
+typedef struct _EFI_IFR_CATENATE {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_CATENATE;
+
+typedef struct _EFI_IFR_DIVIDE {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_DIVIDE;
+
+typedef struct _EFI_IFR_EQUAL {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_EQUAL;
+
+typedef struct _EFI_IFR_GREATER_EQUAL {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_GREATER_EQUAL;
+
+typedef struct _EFI_IFR_GREATER_THAN {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_GREATER_THAN;
+
+typedef struct _EFI_IFR_LESS_EQUAL {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_LESS_EQUAL;
+
+typedef struct _EFI_IFR_LESS_THAN {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_LESS_THAN;
+
+typedef struct _EFI_IFR_MATCH {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_MATCH;
+
+typedef struct _EFI_IFR_MULTIPLY {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_MULTIPLY;
+
+typedef struct _EFI_IFR_MODULO {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_MODULO;
+
+typedef struct _EFI_IFR_NOT_EQUAL {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_NOT_EQUAL;
+
+typedef struct _EFI_IFR_OR {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_OR;
+
+typedef struct _EFI_IFR_SHIFT_LEFT {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_SHIFT_LEFT;
+
+typedef struct _EFI_IFR_SHIFT_RIGHT {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_SHIFT_RIGHT;
+
+typedef struct _EFI_IFR_SUBTRACT {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_SUBTRACT;
+
+typedef struct _EFI_IFR_CONDITIONAL {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_CONDITIONAL;
+
+#define EFI_IFR_FF_CASE_SENSITIVE 0x00
+#define EFI_IFR_FF_CASE_INSENSITIVE 0x01
+
+typedef struct _EFI_IFR_FIND {
+ EFI_IFR_OP_HEADER Header;
+ UINT8 Format;
+} EFI_IFR_FIND;
+
+typedef struct _EFI_IFR_MID {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_MID;
+
+typedef struct _EFI_IFR_TOKEN {
+ EFI_IFR_OP_HEADER Header;
+} EFI_IFR_TOKEN;
+
+#define EFI_IFR_FLAGS_FIRST_MATCHING 0x00
+#define EFI_IFR_FLAGS_FIRST_NON_MATCHING 0x01
+
+typedef struct _EFI_IFR_SPAN {
+ EFI_IFR_OP_HEADER Header;
+ UINT8 Flags;
+} EFI_IFR_SPAN;
+
+//
+// Keyboard Package
+//
+
+typedef enum {
+ EfiKeyLCtrl,
+ EfiKeyA0,
+ EfiKeyLAlt,
+ EfiKeySpaceBar,
+ EfiKeyA2,
+ EfiKeyA3,
+ EfiKeyA4,
+ EfiKeyRCtrl,
+ EfiKeyLeftArrow,
+ EfiKeyDownArrow,
+ EfiKeyRightArrow,
+ EfiKeyZero,
+ EfiKeyPeriod,
+ EfiKeyEnter,
+ EfiKeyLShift,
+ EfiKeyB0,
+ EfiKeyB1,
+ EfiKeyB2,
+ EfiKeyB3,
+ EfiKeyB4,
+ EfiKeyB5,
+ EfiKeyB6,
+ EfiKeyB7,
+ EfiKeyB8,
+ EfiKeyB9,
+ EfiKeyB10,
+ EfiKeyRShift,
+ EfiKeyUpArrow,
+ EfiKeyOne,
+ EfiKeyTwo,
+ EfiKeyThree,
+ EfiKeyCapsLock,
+ EfiKeyC1,
+ EfiKeyC2,
+ EfiKeyC3,
+ EfiKeyC4,
+ EfiKeyC5,
+ EfiKeyC6,
+ EfiKeyC7,
+ EfiKeyC8,
+ EfiKeyC9,
+ EfiKeyC10,
+ EfiKeyC11,
+ EfiKeyC12,
+ EfiKeyFour,
+ EfiKeyFive,
+ EfiKeySix,
+ EfiKeyPlus,
+ EfiKeyTab,
+ EfiKeyD1,
+ EfiKeyD2,
+ EfiKeyD3,
+ EfiKeyD4,
+ EfiKeyD5,
+ EfiKeyD6,
+ EfiKeyD7,
+ EfiKeyD8,
+ EfiKeyD9,
+ EfiKeyD10,
+ EfiKeyD11,
+ EfiKeyD12,
+ EfiKeyD13,
+ EfiKeyDel,
+ EfiKeyEnd,
+ EfiKeyPgDn,
+ EfiKeySeven,
+ EfiKeyEight,
+ EfiKeyNine,
+ EfiKeyE0,
+ EfiKeyE1,
+ EfiKeyE2,
+ EfiKeyE3,
+ EfiKeyE4,
+ EfiKeyE5,
+ EfiKeyE6,
+ EfiKeyE7,
+ EfiKeyE8,
+ EfiKeyE9,
+ EfiKeyE10,
+ EfiKeyE11,
+ EfiKeyE12,
+ EfiKeyBackSpace,
+ EfiKeyIns,
+ EfiKeyHome,
+ EfiKeyPgUp,
+ EfiKeyNLck,
+ EfiKeySlash,
+ EfiKeyAsterisk,
+ EfiKeyMinus,
+ EfiKeyEsc,
+ EfiKeyF1,
+ EfiKeyF2,
+ EfiKeyF3,
+ EfiKeyF4,
+ EfiKeyF5,
+ EfiKeyF6,
+ EfiKeyF7,
+ EfiKeyF8,
+ EfiKeyF9,
+ EfiKeyF10,
+ EfiKeyF11,
+ EfiKeyF12,
+ EfiKeyPrint,
+ EfiKeySLck,
+ EfiKeyPause
+} EFI_KEY;
+
+typedef struct {
+ EFI_KEY Key;
+ CHAR16 Unicode;
+ CHAR16 ShiftedUnicode;
+ CHAR16 AltGrUnicode;
+ CHAR16 ShiftedAltGrUnicode;
+ UINT16 Modifier;
+ UINT16 AffectedAttribute;
+} EFI_KEY_DESCRIPTOR;
+
+///
+/// A key which is affected by all the standard shift modifiers.
+/// Most keys would be expected to have this bit active.
+///
+#define EFI_AFFECTED_BY_STANDARD_SHIFT 0x0001
+
+///
+/// This key is affected by the caps lock so that if a keyboard driver
+/// would need to disambiguate between a key which had a "1" defined
+/// versus a "a" character. Having this bit turned on would tell
+/// the keyboard driver to use the appropriate shifted state or not.
+///
+#define EFI_AFFECTED_BY_CAPS_LOCK 0x0002
+
+///
+/// Similar to the case of CAPS lock, if this bit is active, the key
+/// is affected by the num lock being turned on.
+///
+#define EFI_AFFECTED_BY_NUM_LOCK 0x0004
+
+typedef struct {
+ UINT16 LayoutLength;
+ EFI_GUID Guid;
+ UINT32 LayoutDescriptorStringOffset;
+ UINT8 DescriptorCount;
+ // EFI_KEY_DESCRIPTOR Descriptors[];
+} EFI_HII_KEYBOARD_LAYOUT;
+
+typedef struct {
+ EFI_HII_PACKAGE_HEADER Header;
+ UINT16 LayoutCount;
+ // EFI_HII_KEYBOARD_LAYOUT Layout[];
+} EFI_HII_KEYBOARD_PACKAGE_HDR;
+
+//
+// Modifier values
+//
+#define EFI_NULL_MODIFIER 0x0000
+#define EFI_LEFT_CONTROL_MODIFIER 0x0001
+#define EFI_RIGHT_CONTROL_MODIFIER 0x0002
+#define EFI_LEFT_ALT_MODIFIER 0x0003
+#define EFI_RIGHT_ALT_MODIFIER 0x0004
+#define EFI_ALT_GR_MODIFIER 0x0005
+#define EFI_INSERT_MODIFIER 0x0006
+#define EFI_DELETE_MODIFIER 0x0007
+#define EFI_PAGE_DOWN_MODIFIER 0x0008
+#define EFI_PAGE_UP_MODIFIER 0x0009
+#define EFI_HOME_MODIFIER 0x000A
+#define EFI_END_MODIFIER 0x000B
+#define EFI_LEFT_SHIFT_MODIFIER 0x000C
+#define EFI_RIGHT_SHIFT_MODIFIER 0x000D
+#define EFI_CAPS_LOCK_MODIFIER 0x000E
+#define EFI_NUM_LOCK_MODIFIER 0x000F
+#define EFI_LEFT_ARROW_MODIFIER 0x0010
+#define EFI_RIGHT_ARROW_MODIFIER 0x0011
+#define EFI_DOWN_ARROW_MODIFIER 0x0012
+#define EFI_UP_ARROW_MODIFIER 0x0013
+#define EFI_NS_KEY_MODIFIER 0x0014
+#define EFI_NS_KEY_DEPENDENCY_MODIFIER 0x0015
+#define EFI_FUNCTION_KEY_ONE_MODIFIER 0x0016
+#define EFI_FUNCTION_KEY_TWO_MODIFIER 0x0017
+#define EFI_FUNCTION_KEY_THREE_MODIFIER 0x0018
+#define EFI_FUNCTION_KEY_FOUR_MODIFIER 0x0019
+#define EFI_FUNCTION_KEY_FIVE_MODIFIER 0x001A
+#define EFI_FUNCTION_KEY_SIX_MODIFIER 0x001B
+#define EFI_FUNCTION_KEY_SEVEN_MODIFIER 0x001C
+#define EFI_FUNCTION_KEY_EIGHT_MODIFIER 0x001D
+#define EFI_FUNCTION_KEY_NINE_MODIFIER 0x001E
+#define EFI_FUNCTION_KEY_TEN_MODIFIER 0x001F
+#define EFI_FUNCTION_KEY_ELEVEN_MODIFIER 0x0020
+#define EFI_FUNCTION_KEY_TWELVE_MODIFIER 0x0021
+
+//
+// Keys that have multiple control functions based on modifier
+// settings are handled in the keyboard driver implementation.
+// For instance PRINT_KEY might have a modifier held down and
+// is still a nonprinting character, but might have an alternate
+// control function like SYSREQUEST
+//
+#define EFI_PRINT_MODIFIER 0x0022
+#define EFI_SYS_REQUEST_MODIFIER 0x0023
+#define EFI_SCROLL_LOCK_MODIFIER 0x0024
+#define EFI_PAUSE_MODIFIER 0x0025
+#define EFI_BREAK_MODIFIER 0x0026
+
+#define EFI_LEFT_LOGO_MODIFIER 0x0027
+#define EFI_RIGHT_LOGO_MODIFIER 0x0028
+#define EFI_MENU_MODIFIER 0x0029
+
+#pragma pack()
+
+
+
+///
+/// References to string tokens must use this macro to enable scanning for
+/// token usages.
+///
+///
+/// STRING_TOKEN is not defined in UEFI specification. But it is placed
+/// here for the easy access by C files and VFR source files.
+///
+#define STRING_TOKEN(t) t
+
+#endif
diff --git a/gpxe/src/include/gpxe/efi/Uefi/UefiMultiPhase.h b/gpxe/src/include/gpxe/efi/Uefi/UefiMultiPhase.h
new file mode 100644
index 00000000..c72697a6
--- /dev/null
+++ b/gpxe/src/include/gpxe/efi/Uefi/UefiMultiPhase.h
@@ -0,0 +1,218 @@
+/** @file
+ This includes some definitions introduced in UEFI that will be used in both PEI and DXE phases.
+
+ Copyright (c) 2006, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __UEFI_MULTIPHASE_H__
+#define __UEFI_MULTIPHASE_H__
+
+#include <gpxe/efi/ProcessorBind.h>
+
+///
+/// Enumeration of memory types introduced in UEFI.
+///
+typedef enum {
+ EfiReservedMemoryType,
+ EfiLoaderCode,
+ EfiLoaderData,
+ EfiBootServicesCode,
+ EfiBootServicesData,
+ EfiRuntimeServicesCode,
+ EfiRuntimeServicesData,
+ EfiConventionalMemory,
+ EfiUnusableMemory,
+ EfiACPIReclaimMemory,
+ EfiACPIMemoryNVS,
+ EfiMemoryMappedIO,
+ EfiMemoryMappedIOPortSpace,
+ EfiPalCode,
+ EfiMaxMemoryType
+} EFI_MEMORY_TYPE;
+
+
+///
+/// Data structure that precedes all of the standard EFI table types.
+///
+typedef struct {
+ UINT64 Signature;
+ UINT32 Revision;
+ UINT32 HeaderSize;
+ UINT32 CRC32;
+ UINT32 Reserved;
+} EFI_TABLE_HEADER;
+
+///
+/// Attributes of variable.
+///
+#define EFI_VARIABLE_NON_VOLATILE 0x00000001
+#define EFI_VARIABLE_BOOTSERVICE_ACCESS 0x00000002
+#define EFI_VARIABLE_RUNTIME_ACCESS 0x00000004
+#define EFI_VARIABLE_HARDWARE_ERROR_RECORD 0x00000008
+
+///
+/// This attribute is identified by the mnemonic 'HR'
+/// elsewhere in this specification.
+///
+#define EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS 0x00000010
+
+//
+// _WIN_CERTIFICATE.wCertificateType
+//
+#define WIN_CERT_TYPE_EFI_PKCS115 0x0EF0
+#define WIN_CERT_TYPE_EFI_GUID 0x0EF1
+
+/**
+
+ The WIN_CERTIFICATE structure is part of the PE/COFF
+ specification and has the following definition:
+
+ @param dwLength The length of the entire certificate,
+ including the length of the header, in
+ bytes.
+
+ @param wRevision The revision level of the WIN_CERTIFICATE
+ structure. The current revision level is
+ 0x0200.
+
+ @param wCertificateType The certificate type. See
+ WIN_CERT_TYPE_xxx for the UEFI
+ certificate types. The UEFI
+ specification reserves the range of
+ certificate type values from 0x0EF0
+ to 0x0EFF.
+
+ @param bCertificate The actual certificate. The format of
+ the certificate depends on
+ wCertificateType. The format of the UEFI
+ certificates is defined below.
+
+
+**/
+typedef struct _WIN_CERTIFICATE {
+ UINT32 dwLength;
+ UINT16 wRevision;
+ UINT16 wCertificateType;
+ //UINT8 bCertificate[ANYSIZE_ARRAY];
+} WIN_CERTIFICATE;
+
+///
+/// WIN_CERTIFICATE_UEFI_GUID.CertType
+///
+#define EFI_CERT_TYPE_RSA2048_SHA256_GUID \
+ {0xa7717414, 0xc616, 0x4977, {0x94, 0x20, 0x84, 0x47, 0x12, 0xa7, 0x35, 0xbf } }
+
+///
+/// WIN_CERTIFICATE_UEFI_GUID.CertData
+///
+typedef struct _EFI_CERT_BLOCK_RSA_2048_SHA256 {
+ UINT32 HashType;
+ UINT8 PublicKey[256];
+ UINT8 Signature[256];
+} EFI_CERT_BLOCK_RSA_2048_SHA256;
+
+
+/**
+
+ @param Hdr This is the standard WIN_CERTIFICATE header, where
+ wCertificateType is set to
+ WIN_CERT_TYPE_UEFI_GUID.
+
+ @param CertType This is the unique id which determines the
+ format of the CertData. In this case, the
+ value is EFI_CERT_TYPE_RSA2048_SHA256_GUID.
+
+ @param CertData This is the certificate data. The format of
+ the data is determined by the CertType. In
+ this case the value is
+ EFI_CERT_BLOCK_RSA_2048_SHA256.
+
+**/
+typedef struct _WIN_CERTIFICATE_UEFI_GUID {
+ WIN_CERTIFICATE Hdr;
+ EFI_GUID CertType;
+ // UINT8 CertData[ANYSIZE_ARRAY];
+} WIN_CERTIFICATE_UEFI_GUID;
+
+
+/**
+
+ Certificate which encapsulates the RSASSA_PKCS1-v1_5 digital
+ signature.
+
+ The WIN_CERTIFICATE_UEFI_PKCS1_15 structure is derived from
+ WIN_CERTIFICATE and encapsulate the information needed to
+ implement the RSASSA-PKCS1-v1_5 digital signature algorithm as
+ specified in RFC2437.
+
+ @param Hdr This is the standard WIN_CERTIFICATE header, where
+ wCertificateType is set to
+ WIN_CERT_TYPE_UEFI_PKCS1_15.
+
+ @param HashAlgorithm This is the hashing algorithm which was
+ performed on the UEFI executable when
+ creating the digital signature. It is
+ one of the enumerated values pre-defined
+ in Section 26.4.1. See
+ EFI_HASH_ALGORITHM_x.
+
+ @param Signature This is the actual digital signature. The
+ size of the signature is the same size as
+ the key (1024-bit key is 128 bytes) and can
+ be determined by subtracting the length of
+ the other parts of this header from the
+ total length of the certificate as found in
+ Hdr.dwLength.
+
+**/
+typedef struct _WIN_CERTIFICATE_EFI_PKCS1_15 {
+ WIN_CERTIFICATE Hdr;
+ EFI_GUID HashAlgorithm;
+ // UINT8 Signature[ANYSIZE_ARRAY];
+} WIN_CERTIFICATE_EFI_PKCS1_15;
+
+
+/**
+
+ AuthInfo is a WIN_CERTIFICATE using the wCertificateType
+ WIN_CERTIFICATE_UEFI_GUID and the CertType
+ EFI_CERT_TYPE_RSA2048_SHA256. If the attribute specifies
+ authenticated access, then the Data buffer should begin with an
+ authentication descriptor prior to the data payload and DataSize
+ should reflect the the data.and descriptor size. The caller
+ shall digest the Monotonic Count value and the associated data
+ for the variable update using the SHA-256 1-way hash algorithm.
+ The ensuing the 32-byte digest will be signed using the private
+ key associated w/ the public/private 2048-bit RSA key-pair. The
+ WIN_CERTIFICATE shall be used to describe the signature of the
+ Variable data *Data. In addition, the signature will also
+ include the MonotonicCount value to guard against replay attacks
+
+ @param MonotonicCount Included in the signature of
+ AuthInfo.Used to ensure freshness/no
+ replay. Incremented during each
+ "Write" access.
+
+ @param AuthInfo Provides the authorization for the variable
+ access. It is a signature across the
+ variable data and the Monotonic Count
+ value. Caller uses Private key that is
+ associated with a public key that has been
+ provisioned via the key exchange.
+
+**/
+typedef struct {
+ UINT64 MonotonicCount;
+ WIN_CERTIFICATE_UEFI_GUID AuthInfo;
+} EFI_VARIABLE_AUTHENTICATION;
+
+#endif
+
diff --git a/gpxe/src/include/gpxe/efi/Uefi/UefiPxe.h b/gpxe/src/include/gpxe/efi/Uefi/UefiPxe.h
new file mode 100644
index 00000000..bdc834fc
--- /dev/null
+++ b/gpxe/src/include/gpxe/efi/Uefi/UefiPxe.h
@@ -0,0 +1,1811 @@
+/** @file
+ This header file contains all of the PXE type definitions,
+ structure prototypes, global variables and constants that
+ are needed for porting PXE to EFI.
+
+ Copyright (c) 2006, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+ @par Revision Reference:
+ 32/64-bit PXE specification:
+ alpha-4, 99-Dec-17
+
+**/
+
+#ifndef __EFI_PXE_H__
+#define __EFI_PXE_H__
+
+#pragma pack(1)
+
+
+
+#define PXE_BUSTYPE(a, b, c, d) \
+ ( \
+ (((PXE_UINT32) (d) & 0xFF) << 24) | (((PXE_UINT32) (c) & 0xFF) << 16) | (((PXE_UINT32) (b) & 0xFF) << 8) | \
+ ((PXE_UINT32) (a) & 0xFF) \
+ )
+
+///
+/// UNDI ROM ID and devive ID signature
+///
+#define PXE_BUSTYPE_PXE PXE_BUSTYPE ('!', 'P', 'X', 'E')
+
+///
+/// BUS ROM ID signatures
+///
+#define PXE_BUSTYPE_PCI PXE_BUSTYPE ('P', 'C', 'I', 'R')
+#define PXE_BUSTYPE_PC_CARD PXE_BUSTYPE ('P', 'C', 'C', 'R')
+#define PXE_BUSTYPE_USB PXE_BUSTYPE ('U', 'S', 'B', 'R')
+#define PXE_BUSTYPE_1394 PXE_BUSTYPE ('1', '3', '9', '4')
+
+#define PXE_SWAP_UINT16(n) ((((PXE_UINT16) (n) & 0x00FF) << 8) | (((PXE_UINT16) (n) & 0xFF00) >> 8))
+
+#define PXE_SWAP_UINT32(n) \
+ ((((PXE_UINT32)(n) & 0x000000FF) << 24) | \
+ (((PXE_UINT32)(n) & 0x0000FF00) << 8) | \
+ (((PXE_UINT32)(n) & 0x00FF0000) >> 8) | \
+ (((PXE_UINT32)(n) & 0xFF000000) >> 24))
+
+#define PXE_SWAP_UINT64(n) \
+ ((((PXE_UINT64)(n) & 0x00000000000000FFULL) << 56) | \
+ (((PXE_UINT64)(n) & 0x000000000000FF00ULL) << 40) | \
+ (((PXE_UINT64)(n) & 0x0000000000FF0000ULL) << 24) | \
+ (((PXE_UINT64)(n) & 0x00000000FF000000ULL) << 8) | \
+ (((PXE_UINT64)(n) & 0x000000FF00000000ULL) >> 8) | \
+ (((PXE_UINT64)(n) & 0x0000FF0000000000ULL) >> 24) | \
+ (((PXE_UINT64)(n) & 0x00FF000000000000ULL) >> 40) | \
+ (((PXE_UINT64)(n) & 0xFF00000000000000ULL) >> 56))
+
+
+#define PXE_CPBSIZE_NOT_USED 0 // zero
+#define PXE_DBSIZE_NOT_USED 0 // zero
+#define PXE_CPBADDR_NOT_USED (PXE_UINT64) 0 // zero
+#define PXE_DBADDR_NOT_USED (PXE_UINT64) 0 // zero
+#define PXE_CONST const
+
+#define PXE_VOLATILE volatile
+
+typedef VOID PXE_VOID;
+typedef UINT8 PXE_UINT8;
+typedef UINT16 PXE_UINT16;
+typedef UINT32 PXE_UINT32;
+typedef UINTN PXE_UINTN;
+
+///
+/// typedef unsigned long PXE_UINT64;
+///
+typedef UINT64 PXE_UINT64;
+
+typedef PXE_UINT8 PXE_BOOL;
+#define PXE_FALSE 0 // zero
+#define PXE_TRUE (!PXE_FALSE)
+
+typedef PXE_UINT16 PXE_OPCODE;
+
+///
+/// Return UNDI operational state.
+///
+#define PXE_OPCODE_GET_STATE 0x0000
+
+///
+/// Change UNDI operational state from Stopped to Started.
+///
+#define PXE_OPCODE_START 0x0001
+
+///
+/// Change UNDI operational state from Started to Stopped.
+///
+#define PXE_OPCODE_STOP 0x0002
+
+///
+/// Get UNDI initialization information.
+///
+#define PXE_OPCODE_GET_INIT_INFO 0x0003
+
+///
+/// Get NIC configuration information.
+///
+#define PXE_OPCODE_GET_CONFIG_INFO 0x0004
+
+///
+/// Changed UNDI operational state from Started to Initialized.
+///
+#define PXE_OPCODE_INITIALIZE 0x0005
+
+///
+/// Re-initialize the NIC H/W.
+///
+#define PXE_OPCODE_RESET 0x0006
+
+///
+/// Change the UNDI operational state from Initialized to Started.
+///
+#define PXE_OPCODE_SHUTDOWN 0x0007
+
+///
+/// Read & change state of external interrupt enables.
+///
+#define PXE_OPCODE_INTERRUPT_ENABLES 0x0008
+
+///
+/// Read & change state of packet receive filters.
+///
+#define PXE_OPCODE_RECEIVE_FILTERS 0x0009
+
+///
+/// Read & change station MAC address.
+///
+#define PXE_OPCODE_STATION_ADDRESS 0x000A
+
+///
+/// Read traffic statistics.
+///
+#define PXE_OPCODE_STATISTICS 0x000B
+
+///
+/// Convert multicast IP address to multicast MAC address.
+///
+#define PXE_OPCODE_MCAST_IP_TO_MAC 0x000C
+
+///
+/// Read or change non-volatile storage on the NIC.
+///
+#define PXE_OPCODE_NVDATA 0x000D
+
+///
+/// Get & clear interrupt status.
+///
+#define PXE_OPCODE_GET_STATUS 0x000E
+
+///
+/// Fill media header in packet for transmit.
+///
+#define PXE_OPCODE_FILL_HEADER 0x000F
+
+///
+/// Transmit packet(s).
+///
+#define PXE_OPCODE_TRANSMIT 0x0010
+
+///
+/// Receive packet.
+///
+#define PXE_OPCODE_RECEIVE 0x0011
+
+///
+/// Last valid PXE UNDI OpCode number.
+///
+#define PXE_OPCODE_LAST_VALID 0x0011
+
+typedef PXE_UINT16 PXE_OPFLAGS;
+
+#define PXE_OPFLAGS_NOT_USED 0x0000
+
+//
+// //////////////////////////////////////
+// UNDI Get State
+//
+// No OpFlags
+
+////////////////////////////////////////
+// UNDI Start
+//
+// No OpFlags
+
+////////////////////////////////////////
+// UNDI Stop
+//
+// No OpFlags
+
+////////////////////////////////////////
+// UNDI Get Init Info
+//
+// No Opflags
+
+////////////////////////////////////////
+// UNDI Get Config Info
+//
+// No Opflags
+
+////////////////////////////////////////
+// UNDI Initialize
+//
+#define PXE_OPFLAGS_INITIALIZE_CABLE_DETECT_MASK 0x0001
+#define PXE_OPFLAGS_INITIALIZE_DETECT_CABLE 0x0000
+#define PXE_OPFLAGS_INITIALIZE_DO_NOT_DETECT_CABLE 0x0001
+
+//
+// //////////////////////////////////////
+// UNDI Reset
+//
+#define PXE_OPFLAGS_RESET_DISABLE_INTERRUPTS 0x0001
+#define PXE_OPFLAGS_RESET_DISABLE_FILTERS 0x0002
+
+//
+// //////////////////////////////////////
+// UNDI Shutdown
+//
+// No OpFlags
+
+////////////////////////////////////////
+// UNDI Interrupt Enables
+//
+//
+// Select whether to enable or disable external interrupt signals.
+// Setting both enable and disable will return PXE_STATCODE_INVALID_OPFLAGS.
+//
+#define PXE_OPFLAGS_INTERRUPT_OPMASK 0xC000
+#define PXE_OPFLAGS_INTERRUPT_ENABLE 0x8000
+#define PXE_OPFLAGS_INTERRUPT_DISABLE 0x4000
+#define PXE_OPFLAGS_INTERRUPT_READ 0x0000
+
+///
+/// Enable receive interrupts. An external interrupt will be generated
+/// after a complete non-error packet has been received.
+///
+#define PXE_OPFLAGS_INTERRUPT_RECEIVE 0x0001
+
+///
+/// Enable transmit interrupts. An external interrupt will be generated
+/// after a complete non-error packet has been transmitted.
+///
+#define PXE_OPFLAGS_INTERRUPT_TRANSMIT 0x0002
+
+///
+/// Enable command interrupts. An external interrupt will be generated
+/// when command execution stops.
+///
+#define PXE_OPFLAGS_INTERRUPT_COMMAND 0x0004
+
+///
+/// Generate software interrupt. Setting this bit generates an external
+/// interrupt, if it is supported by the hardware.
+///
+#define PXE_OPFLAGS_INTERRUPT_SOFTWARE 0x0008
+
+//
+// //////////////////////////////////////
+// UNDI Receive Filters
+//
+//
+// Select whether to enable or disable receive filters.
+// Setting both enable and disable will return PXE_STATCODE_INVALID_OPCODE.
+//
+#define PXE_OPFLAGS_RECEIVE_FILTER_OPMASK 0xC000
+#define PXE_OPFLAGS_RECEIVE_FILTER_ENABLE 0x8000
+#define PXE_OPFLAGS_RECEIVE_FILTER_DISABLE 0x4000
+#define PXE_OPFLAGS_RECEIVE_FILTER_READ 0x0000
+
+///
+/// To reset the contents of the multicast MAC address filter list,
+/// set this OpFlag:
+///
+#define PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST 0x2000
+
+///
+/// Enable unicast packet receiving. Packets sent to the current station
+/// MAC address will be received.
+///
+#define PXE_OPFLAGS_RECEIVE_FILTER_UNICAST 0x0001
+
+///
+/// Enable broadcast packet receiving. Packets sent to the broadcast
+/// MAC address will be received.
+///
+#define PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST 0x0002
+
+///
+/// Enable filtered multicast packet receiving. Packets sent to any
+/// of the multicast MAC addresses in the multicast MAC address filter
+/// list will be received. If the filter list is empty, no multicast
+///
+#define PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST 0x0004
+
+///
+/// Enable promiscuous packet receiving. All packets will be received.
+///
+#define PXE_OPFLAGS_RECEIVE_FILTER_PROMISCUOUS 0x0008
+
+///
+/// Enable promiscuous multicast packet receiving. All multicast
+/// packets will be received.
+///
+#define PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST 0x0010
+
+//
+// //////////////////////////////////////
+// UNDI Station Address
+//
+#define PXE_OPFLAGS_STATION_ADDRESS_READ 0x0000
+#define PXE_OPFLAGS_STATION_ADDRESS_WRITE 0x0000
+#define PXE_OPFLAGS_STATION_ADDRESS_RESET 0x0001
+
+//
+// //////////////////////////////////////
+// UNDI Statistics
+//
+#define PXE_OPFLAGS_STATISTICS_READ 0x0000
+#define PXE_OPFLAGS_STATISTICS_RESET 0x0001
+
+//
+// //////////////////////////////////////
+// UNDI MCast IP to MAC
+//
+//
+// Identify the type of IP address in the CPB.
+//
+#define PXE_OPFLAGS_MCAST_IP_TO_MAC_OPMASK 0x0003
+#define PXE_OPFLAGS_MCAST_IPV4_TO_MAC 0x0000
+#define PXE_OPFLAGS_MCAST_IPV6_TO_MAC 0x0001
+
+//
+// //////////////////////////////////////
+// UNDI NvData
+//
+//
+// Select the type of non-volatile data operation.
+//
+#define PXE_OPFLAGS_NVDATA_OPMASK 0x0001
+#define PXE_OPFLAGS_NVDATA_READ 0x0000
+#define PXE_OPFLAGS_NVDATA_WRITE 0x0001
+
+//
+// //////////////////////////////////////
+// UNDI Get Status
+//
+//
+// Return current interrupt status. This will also clear any interrupts
+// that are currently set. This can be used in a polling routine. The
+// interrupt flags are still set and cleared even when the interrupts
+// are disabled.
+//
+#define PXE_OPFLAGS_GET_INTERRUPT_STATUS 0x0001
+
+//
+// Return list of transmitted buffers for recycling. Transmit buffers
+// must not be changed or unallocated until they have recycled. After
+// issuing a transmit command, wait for a transmit complete interrupt.
+// When a transmit complete interrupt is received, read the transmitted
+// buffers. Do not plan on getting one buffer per interrupt. Some
+// NICs and UNDIs may transmit multiple buffers per interrupt.
+//
+#define PXE_OPFLAGS_GET_TRANSMITTED_BUFFERS 0x0002
+
+//
+// //////////////////////////////////////
+// UNDI Fill Header
+//
+#define PXE_OPFLAGS_FILL_HEADER_OPMASK 0x0001
+#define PXE_OPFLAGS_FILL_HEADER_FRAGMENTED 0x0001
+#define PXE_OPFLAGS_FILL_HEADER_WHOLE 0x0000
+
+//
+// //////////////////////////////////////
+// UNDI Transmit
+//
+//
+// S/W UNDI only. Return after the packet has been transmitted. A
+// transmit complete interrupt will still be generated and the transmit
+// buffer will have to be recycled.
+//
+#define PXE_OPFLAGS_SWUNDI_TRANSMIT_OPMASK 0x0001
+#define PXE_OPFLAGS_TRANSMIT_BLOCK 0x0001
+#define PXE_OPFLAGS_TRANSMIT_DONT_BLOCK 0x0000
+
+//
+//
+//
+#define PXE_OPFLAGS_TRANSMIT_OPMASK 0x0002
+#define PXE_OPFLAGS_TRANSMIT_FRAGMENTED 0x0002
+#define PXE_OPFLAGS_TRANSMIT_WHOLE 0x0000
+
+//
+// //////////////////////////////////////
+// UNDI Receive
+//
+// No OpFlags
+//
+typedef PXE_UINT16 PXE_STATFLAGS;
+
+#define PXE_STATFLAGS_INITIALIZE 0x0000
+
+//
+// //////////////////////////////////////
+// Common StatFlags that can be returned by all commands.
+//
+//
+// The COMMAND_COMPLETE and COMMAND_FAILED status flags must be
+// implemented by all UNDIs. COMMAND_QUEUED is only needed by UNDIs
+// that support command queuing.
+//
+#define PXE_STATFLAGS_STATUS_MASK 0xC000
+#define PXE_STATFLAGS_COMMAND_COMPLETE 0xC000
+#define PXE_STATFLAGS_COMMAND_FAILED 0x8000
+#define PXE_STATFLAGS_COMMAND_QUEUED 0x4000
+
+//
+// //////////////////////////////////////
+// UNDI Get State
+//
+#define PXE_STATFLAGS_GET_STATE_MASK 0x0003
+#define PXE_STATFLAGS_GET_STATE_INITIALIZED 0x0002
+#define PXE_STATFLAGS_GET_STATE_STARTED 0x0001
+#define PXE_STATFLAGS_GET_STATE_STOPPED 0x0000
+
+//
+// //////////////////////////////////////
+// UNDI Start
+//
+// No additional StatFlags
+
+////////////////////////////////////////
+// UNDI Get Init Info
+//
+#define PXE_STATFLAGS_CABLE_DETECT_MASK 0x0001
+#define PXE_STATFLAGS_CABLE_DETECT_NOT_SUPPORTED 0x0000
+#define PXE_STATFLAGS_CABLE_DETECT_SUPPORTED 0x0001
+
+//
+// //////////////////////////////////////
+// UNDI Initialize
+//
+#define PXE_STATFLAGS_INITIALIZED_NO_MEDIA 0x0001
+
+//
+// //////////////////////////////////////
+// UNDI Reset
+//
+#define PXE_STATFLAGS_RESET_NO_MEDIA 0x0001
+
+//
+// //////////////////////////////////////
+// UNDI Shutdown
+//
+// No additional StatFlags
+
+////////////////////////////////////////
+// UNDI Interrupt Enables
+//
+//
+// If set, receive interrupts are enabled.
+//
+#define PXE_STATFLAGS_INTERRUPT_RECEIVE 0x0001
+
+//
+// If set, transmit interrupts are enabled.
+//
+#define PXE_STATFLAGS_INTERRUPT_TRANSMIT 0x0002
+
+//
+// If set, command interrupts are enabled.
+//
+#define PXE_STATFLAGS_INTERRUPT_COMMAND 0x0004
+
+//
+// //////////////////////////////////////
+// UNDI Receive Filters
+//
+//
+// If set, unicast packets will be received.
+//
+#define PXE_STATFLAGS_RECEIVE_FILTER_UNICAST 0x0001
+
+//
+// If set, broadcast packets will be received.
+//
+#define PXE_STATFLAGS_RECEIVE_FILTER_BROADCAST 0x0002
+
+//
+// If set, multicast packets that match up with the multicast address
+// filter list will be received.
+//
+#define PXE_STATFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST 0x0004
+
+//
+// If set, all packets will be received.
+//
+#define PXE_STATFLAGS_RECEIVE_FILTER_PROMISCUOUS 0x0008
+
+//
+// If set, all multicast packets will be received.
+//
+#define PXE_STATFLAGS_RECEIVE_FILTER_ALL_MULTICAST 0x0010
+
+//
+// //////////////////////////////////////
+// UNDI Station Address
+//
+// No additional StatFlags
+
+////////////////////////////////////////
+// UNDI Statistics
+//
+// No additional StatFlags
+
+////////////////////////////////////////
+// UNDI MCast IP to MAC
+//
+// No additional StatFlags
+
+////////////////////////////////////////
+// UNDI NvData
+//
+// No additional StatFlags
+
+
+////////////////////////////////////////
+// UNDI Get Status
+//
+//
+// Use to determine if an interrupt has occurred.
+//
+#define PXE_STATFLAGS_GET_STATUS_INTERRUPT_MASK 0x000F
+#define PXE_STATFLAGS_GET_STATUS_NO_INTERRUPTS 0x0000
+
+//
+// If set, at least one receive interrupt occurred.
+//
+#define PXE_STATFLAGS_GET_STATUS_RECEIVE 0x0001
+
+//
+// If set, at least one transmit interrupt occurred.
+//
+#define PXE_STATFLAGS_GET_STATUS_TRANSMIT 0x0002
+
+//
+// If set, at least one command interrupt occurred.
+//
+#define PXE_STATFLAGS_GET_STATUS_COMMAND 0x0004
+
+//
+// If set, at least one software interrupt occurred.
+//
+#define PXE_STATFLAGS_GET_STATUS_SOFTWARE 0x0008
+
+//
+// This flag is set if the transmitted buffer queue is empty. This flag
+// will be set if all transmitted buffer addresses get written into the DB.
+//
+#define PXE_STATFLAGS_GET_STATUS_TXBUF_QUEUE_EMPTY 0x0010
+
+//
+// This flag is set if no transmitted buffer addresses were written
+// into the DB. (This could be because DBsize was too small.)
+//
+#define PXE_STATFLAGS_GET_STATUS_NO_TXBUFS_WRITTEN 0x0020
+
+//
+// //////////////////////////////////////
+// UNDI Fill Header
+//
+// No additional StatFlags
+
+////////////////////////////////////////
+// UNDI Transmit
+//
+// No additional StatFlags.
+
+////////////////////////////////////////
+// UNDI Receive
+//
+// No additional StatFlags.
+//
+typedef PXE_UINT16 PXE_STATCODE;
+
+#define PXE_STATCODE_INITIALIZE 0x0000
+
+//
+// //////////////////////////////////////
+// Common StatCodes returned by all UNDI commands, UNDI protocol functions
+// and BC protocol functions.
+//
+#define PXE_STATCODE_SUCCESS 0x0000
+
+#define PXE_STATCODE_INVALID_CDB 0x0001
+#define PXE_STATCODE_INVALID_CPB 0x0002
+#define PXE_STATCODE_BUSY 0x0003
+#define PXE_STATCODE_QUEUE_FULL 0x0004
+#define PXE_STATCODE_ALREADY_STARTED 0x0005
+#define PXE_STATCODE_NOT_STARTED 0x0006
+#define PXE_STATCODE_NOT_SHUTDOWN 0x0007
+#define PXE_STATCODE_ALREADY_INITIALIZED 0x0008
+#define PXE_STATCODE_NOT_INITIALIZED 0x0009
+#define PXE_STATCODE_DEVICE_FAILURE 0x000A
+#define PXE_STATCODE_NVDATA_FAILURE 0x000B
+#define PXE_STATCODE_UNSUPPORTED 0x000C
+#define PXE_STATCODE_BUFFER_FULL 0x000D
+#define PXE_STATCODE_INVALID_PARAMETER 0x000E
+#define PXE_STATCODE_INVALID_UNDI 0x000F
+#define PXE_STATCODE_IPV4_NOT_SUPPORTED 0x0010
+#define PXE_STATCODE_IPV6_NOT_SUPPORTED 0x0011
+#define PXE_STATCODE_NOT_ENOUGH_MEMORY 0x0012
+#define PXE_STATCODE_NO_DATA 0x0013
+
+typedef PXE_UINT16 PXE_IFNUM;
+
+//
+// This interface number must be passed to the S/W UNDI Start command.
+//
+#define PXE_IFNUM_START 0x0000
+
+//
+// This interface number is returned by the S/W UNDI Get State and
+// Start commands if information in the CDB, CPB or DB is invalid.
+//
+#define PXE_IFNUM_INVALID 0x0000
+
+typedef PXE_UINT16 PXE_CONTROL;
+
+//
+// Setting this flag directs the UNDI to queue this command for later
+// execution if the UNDI is busy and it supports command queuing.
+// If queuing is not supported, a PXE_STATCODE_INVALID_CONTROL error
+// is returned. If the queue is full, a PXE_STATCODE_CDB_QUEUE_FULL
+// error is returned.
+//
+#define PXE_CONTROL_QUEUE_IF_BUSY 0x0002
+
+//
+// These two bit values are used to determine if there are more UNDI
+// CDB structures following this one. If the link bit is set, there
+// must be a CDB structure following this one. Execution will start
+// on the next CDB structure as soon as this one completes successfully.
+// If an error is generated by this command, execution will stop.
+//
+#define PXE_CONTROL_LINK 0x0001
+#define PXE_CONTROL_LAST_CDB_IN_LIST 0x0000
+
+typedef PXE_UINT8 PXE_FRAME_TYPE;
+
+#define PXE_FRAME_TYPE_NONE 0x00
+#define PXE_FRAME_TYPE_UNICAST 0x01
+#define PXE_FRAME_TYPE_BROADCAST 0x02
+#define PXE_FRAME_TYPE_FILTERED_MULTICAST 0x03
+#define PXE_FRAME_TYPE_PROMISCUOUS 0x04
+#define PXE_FRAME_TYPE_PROMISCUOUS_MULTICAST 0x05
+
+#define PXE_FRAME_TYPE_MULTICAST PXE_FRAME_TYPE_FILTERED_MULTICAST
+
+typedef PXE_UINT32 PXE_IPV4;
+
+typedef PXE_UINT32 PXE_IPV6[4];
+#define PXE_MAC_LENGTH 32
+
+typedef PXE_UINT8 PXE_MAC_ADDR[PXE_MAC_LENGTH];
+
+typedef PXE_UINT8 PXE_IFTYPE;
+typedef UINT16 PXE_MEDIA_PROTOCOL;
+
+//
+// This information is from the ARP section of RFC 1700.
+//
+// 1 Ethernet (10Mb) [JBP]
+// 2 Experimental Ethernet (3Mb) [JBP]
+// 3 Amateur Radio AX.25 [PXK]
+// 4 Proteon ProNET Token Ring [JBP]
+// 5 Chaos [GXP]
+// 6 IEEE 802 Networks [JBP]
+// 7 ARCNET [JBP]
+// 8 Hyperchannel [JBP]
+// 9 Lanstar [TU]
+// 10 Autonet Short Address [MXB1]
+// 11 LocalTalk [JKR1]
+// 12 LocalNet (IBM* PCNet or SYTEK* LocalNET) [JXM]
+// 13 Ultra link [RXD2]
+// 14 SMDS [GXC1]
+// 15 Frame Relay [AGM]
+// 16 Asynchronous Transmission Mode (ATM) [JXB2]
+// 17 HDLC [JBP]
+// 18 Fibre Channel [Yakov Rekhter]
+// 19 Asynchronous Transmission Mode (ATM) [Mark Laubach]
+// 20 Serial Line [JBP]
+// 21 Asynchronous Transmission Mode (ATM) [MXB1]
+//
+// * Other names and brands may be claimed as the property of others.
+//
+#define PXE_IFTYPE_ETHERNET 0x01
+#define PXE_IFTYPE_TOKENRING 0x04
+#define PXE_IFTYPE_FIBRE_CHANNEL 0x12
+
+typedef struct s_pxe_hw_undi {
+ PXE_UINT32 Signature; // PXE_ROMID_SIGNATURE
+ PXE_UINT8 Len; // sizeof(PXE_HW_UNDI)
+ PXE_UINT8 Fudge; // makes 8-bit cksum equal zero
+ PXE_UINT8 Rev; // PXE_ROMID_REV
+ PXE_UINT8 IFcnt; // physical connector count
+ PXE_UINT8 MajorVer; // PXE_ROMID_MAJORVER
+ PXE_UINT8 MinorVer; // PXE_ROMID_MINORVER
+ PXE_UINT16 reserved; // zero, not used
+ PXE_UINT32 Implementation; // implementation flags
+ // reserved // vendor use
+ // UINT32 Status; // status port
+ // UINT32 Command; // command port
+ // UINT64 CDBaddr; // CDB address port
+ //
+} PXE_HW_UNDI;
+
+//
+// Status port bit definitions
+//
+//
+// UNDI operation state
+//
+#define PXE_HWSTAT_STATE_MASK 0xC0000000
+#define PXE_HWSTAT_BUSY 0xC0000000
+#define PXE_HWSTAT_INITIALIZED 0x80000000
+#define PXE_HWSTAT_STARTED 0x40000000
+#define PXE_HWSTAT_STOPPED 0x00000000
+
+//
+// If set, last command failed
+//
+#define PXE_HWSTAT_COMMAND_FAILED 0x20000000
+
+//
+// If set, identifies enabled receive filters
+//
+#define PXE_HWSTAT_PROMISCUOUS_MULTICAST_RX_ENABLED 0x00001000
+#define PXE_HWSTAT_PROMISCUOUS_RX_ENABLED 0x00000800
+#define PXE_HWSTAT_BROADCAST_RX_ENABLED 0x00000400
+#define PXE_HWSTAT_MULTICAST_RX_ENABLED 0x00000200
+#define PXE_HWSTAT_UNICAST_RX_ENABLED 0x00000100
+
+//
+// If set, identifies enabled external interrupts
+//
+#define PXE_HWSTAT_SOFTWARE_INT_ENABLED 0x00000080
+#define PXE_HWSTAT_TX_COMPLETE_INT_ENABLED 0x00000040
+#define PXE_HWSTAT_PACKET_RX_INT_ENABLED 0x00000020
+#define PXE_HWSTAT_CMD_COMPLETE_INT_ENABLED 0x00000010
+
+//
+// If set, identifies pending interrupts
+//
+#define PXE_HWSTAT_SOFTWARE_INT_PENDING 0x00000008
+#define PXE_HWSTAT_TX_COMPLETE_INT_PENDING 0x00000004
+#define PXE_HWSTAT_PACKET_RX_INT_PENDING 0x00000002
+#define PXE_HWSTAT_CMD_COMPLETE_INT_PENDING 0x00000001
+
+//
+// Command port definitions
+//
+//
+// If set, CDB identified in CDBaddr port is given to UNDI.
+// If not set, other bits in this word will be processed.
+//
+#define PXE_HWCMD_ISSUE_COMMAND 0x80000000
+#define PXE_HWCMD_INTS_AND_FILTS 0x00000000
+
+//
+// Use these to enable/disable receive filters.
+//
+#define PXE_HWCMD_PROMISCUOUS_MULTICAST_RX_ENABLE 0x00001000
+#define PXE_HWCMD_PROMISCUOUS_RX_ENABLE 0x00000800
+#define PXE_HWCMD_BROADCAST_RX_ENABLE 0x00000400
+#define PXE_HWCMD_MULTICAST_RX_ENABLE 0x00000200
+#define PXE_HWCMD_UNICAST_RX_ENABLE 0x00000100
+
+//
+// Use these to enable/disable external interrupts
+//
+#define PXE_HWCMD_SOFTWARE_INT_ENABLE 0x00000080
+#define PXE_HWCMD_TX_COMPLETE_INT_ENABLE 0x00000040
+#define PXE_HWCMD_PACKET_RX_INT_ENABLE 0x00000020
+#define PXE_HWCMD_CMD_COMPLETE_INT_ENABLE 0x00000010
+
+//
+// Use these to clear pending external interrupts
+//
+#define PXE_HWCMD_CLEAR_SOFTWARE_INT 0x00000008
+#define PXE_HWCMD_CLEAR_TX_COMPLETE_INT 0x00000004
+#define PXE_HWCMD_CLEAR_PACKET_RX_INT 0x00000002
+#define PXE_HWCMD_CLEAR_CMD_COMPLETE_INT 0x00000001
+
+typedef struct s_pxe_sw_undi {
+ PXE_UINT32 Signature; // PXE_ROMID_SIGNATURE
+ PXE_UINT8 Len; // sizeof(PXE_SW_UNDI)
+ PXE_UINT8 Fudge; // makes 8-bit cksum zero
+ PXE_UINT8 Rev; // PXE_ROMID_REV
+ PXE_UINT8 IFcnt; // physical connector count
+ PXE_UINT8 MajorVer; // PXE_ROMID_MAJORVER
+ PXE_UINT8 MinorVer; // PXE_ROMID_MINORVER
+ PXE_UINT16 reserved1; // zero, not used
+ PXE_UINT32 Implementation; // Implementation flags
+ PXE_UINT64 EntryPoint; // API entry point
+ PXE_UINT8 reserved2[3]; // zero, not used
+ PXE_UINT8 BusCnt; // number of bustypes supported
+ PXE_UINT32 BusType[1]; // list of supported bustypes
+} PXE_SW_UNDI;
+
+typedef union u_pxe_undi {
+ PXE_HW_UNDI hw;
+ PXE_SW_UNDI sw;
+} PXE_UNDI;
+
+//
+// Signature of !PXE structure
+//
+#define PXE_ROMID_SIGNATURE PXE_BUSTYPE ('!', 'P', 'X', 'E')
+
+//
+// !PXE structure format revision
+//
+#define PXE_ROMID_REV 0x02
+
+//
+// UNDI command interface revision. These are the values that get sent
+// in option 94 (Client Network Interface Identifier) in the DHCP Discover
+// and PXE Boot Server Request packets.
+//
+#define PXE_ROMID_MAJORVER 0x03
+#define PXE_ROMID_MINORVER 0x01
+
+//
+// Implementation flags
+//
+#define PXE_ROMID_IMP_HW_UNDI 0x80000000
+#define PXE_ROMID_IMP_SW_VIRT_ADDR 0x40000000
+#define PXE_ROMID_IMP_64BIT_DEVICE 0x00010000
+#define PXE_ROMID_IMP_FRAG_SUPPORTED 0x00008000
+#define PXE_ROMID_IMP_CMD_LINK_SUPPORTED 0x00004000
+#define PXE_ROMID_IMP_CMD_QUEUE_SUPPORTED 0x00002000
+#define PXE_ROMID_IMP_MULTI_FRAME_SUPPORTED 0x00001000
+#define PXE_ROMID_IMP_NVDATA_SUPPORT_MASK 0x00000C00
+#define PXE_ROMID_IMP_NVDATA_BULK_WRITABLE 0x00000C00
+#define PXE_ROMID_IMP_NVDATA_SPARSE_WRITABLE 0x00000800
+#define PXE_ROMID_IMP_NVDATA_READ_ONLY 0x00000400
+#define PXE_ROMID_IMP_NVDATA_NOT_AVAILABLE 0x00000000
+#define PXE_ROMID_IMP_STATISTICS_SUPPORTED 0x00000200
+#define PXE_ROMID_IMP_STATION_ADDR_SETTABLE 0x00000100
+#define PXE_ROMID_IMP_PROMISCUOUS_MULTICAST_RX_SUPPORTED 0x00000080
+#define PXE_ROMID_IMP_PROMISCUOUS_RX_SUPPORTED 0x00000040
+#define PXE_ROMID_IMP_BROADCAST_RX_SUPPORTED 0x00000020
+#define PXE_ROMID_IMP_FILTERED_MULTICAST_RX_SUPPORTED 0x00000010
+#define PXE_ROMID_IMP_SOFTWARE_INT_SUPPORTED 0x00000008
+#define PXE_ROMID_IMP_TX_COMPLETE_INT_SUPPORTED 0x00000004
+#define PXE_ROMID_IMP_PACKET_RX_INT_SUPPORTED 0x00000002
+#define PXE_ROMID_IMP_CMD_COMPLETE_INT_SUPPORTED 0x00000001
+
+typedef struct s_pxe_cdb {
+ PXE_OPCODE OpCode;
+ PXE_OPFLAGS OpFlags;
+ PXE_UINT16 CPBsize;
+ PXE_UINT16 DBsize;
+ PXE_UINT64 CPBaddr;
+ PXE_UINT64 DBaddr;
+ PXE_STATCODE StatCode;
+ PXE_STATFLAGS StatFlags;
+ PXE_UINT16 IFnum;
+ PXE_CONTROL Control;
+} PXE_CDB;
+
+typedef union u_pxe_ip_addr {
+ PXE_IPV6 IPv6;
+ PXE_IPV4 IPv4;
+} PXE_IP_ADDR;
+
+typedef union pxe_device {
+ //
+ // PCI and PC Card NICs are both identified using bus, device
+ // and function numbers. For PC Card, this may require PC
+ // Card services to be loaded in the BIOS or preboot
+ // environment.
+ //
+ struct {
+ //
+ // See S/W UNDI ROMID structure definition for PCI and
+ // PCC BusType definitions.
+ //
+ PXE_UINT32 BusType;
+
+ //
+ // Bus, device & function numbers that locate this device.
+ //
+ PXE_UINT16 Bus;
+ PXE_UINT8 Device;
+ PXE_UINT8 Function;
+ }
+ PCI, PCC;
+
+ //
+ // %%TBD - More information is needed about enumerating
+ // USB and 1394 devices.
+ //
+ struct {
+ PXE_UINT32 BusType;
+ PXE_UINT32 tdb;
+ }
+ USB, _1394;
+} PXE_DEVICE;
+
+//
+// cpb and db definitions
+//
+#define MAX_PCI_CONFIG_LEN 64 // # of dwords
+#define MAX_EEPROM_LEN 128 // #of dwords
+#define MAX_XMIT_BUFFERS 32 // recycling Q length for xmit_done
+#define MAX_MCAST_ADDRESS_CNT 8
+
+typedef struct s_pxe_cpb_start_30 {
+ //
+ // PXE_VOID Delay(UINTN microseconds);
+ //
+ // UNDI will never request a delay smaller than 10 microseconds
+ // and will always request delays in increments of 10 microseconds.
+ // The Delay() CallBack routine must delay between n and n + 10
+ // microseconds before returning control to the UNDI.
+ //
+ // This field cannot be set to zero.
+ //
+ UINT64 Delay;
+
+ //
+ // PXE_VOID Block(UINT32 enable);
+ //
+ // UNDI may need to block multi-threaded/multi-processor access to
+ // critical code sections when programming or accessing the network
+ // device. To this end, a blocking service is needed by the UNDI.
+ // When UNDI needs a block, it will call Block() passing a non-zero
+ // value. When UNDI no longer needs a block, it will call Block()
+ // with a zero value. When called, if the Block() is already enabled,
+ // do not return control to the UNDI until the previous Block() is
+ // disabled.
+ //
+ // This field cannot be set to zero.
+ //
+ UINT64 Block;
+
+ //
+ // PXE_VOID Virt2Phys(UINT64 virtual, UINT64 physical_ptr);
+ //
+ // UNDI will pass the virtual address of a buffer and the virtual
+ // address of a 64-bit physical buffer. Convert the virtual address
+ // to a physical address and write the result to the physical address
+ // buffer. If virtual and physical addresses are the same, just
+ // copy the virtual address to the physical address buffer.
+ //
+ // This field can be set to zero if virtual and physical addresses
+ // are equal.
+ //
+ UINT64 Virt2Phys;
+ //
+ // PXE_VOID Mem_IO(UINT8 read_write, UINT8 len, UINT64 port,
+ // UINT64 buf_addr);
+ //
+ // UNDI will read or write the device io space using this call back
+ // function. It passes the number of bytes as the len parameter and it
+ // will be either 1,2,4 or 8.
+ //
+ // This field can not be set to zero.
+ //
+ UINT64 Mem_IO;
+} PXE_CPB_START_30;
+
+typedef struct s_pxe_cpb_start_31 {
+ //
+ // PXE_VOID Delay(UINT64 UnqId, UINTN microseconds);
+ //
+ // UNDI will never request a delay smaller than 10 microseconds
+ // and will always request delays in increments of 10 microseconds.
+ // The Delay() CallBack routine must delay between n and n + 10
+ // microseconds before returning control to the UNDI.
+ //
+ // This field cannot be set to zero.
+ //
+ UINT64 Delay;
+
+ //
+ // PXE_VOID Block(UINT64 unq_id, UINT32 enable);
+ //
+ // UNDI may need to block multi-threaded/multi-processor access to
+ // critical code sections when programming or accessing the network
+ // device. To this end, a blocking service is needed by the UNDI.
+ // When UNDI needs a block, it will call Block() passing a non-zero
+ // value. When UNDI no longer needs a block, it will call Block()
+ // with a zero value. When called, if the Block() is already enabled,
+ // do not return control to the UNDI until the previous Block() is
+ // disabled.
+ //
+ // This field cannot be set to zero.
+ //
+ UINT64 Block;
+
+ //
+ // PXE_VOID Virt2Phys(UINT64 UnqId, UINT64 virtual, UINT64 physical_ptr);
+ //
+ // UNDI will pass the virtual address of a buffer and the virtual
+ // address of a 64-bit physical buffer. Convert the virtual address
+ // to a physical address and write the result to the physical address
+ // buffer. If virtual and physical addresses are the same, just
+ // copy the virtual address to the physical address buffer.
+ //
+ // This field can be set to zero if virtual and physical addresses
+ // are equal.
+ //
+ UINT64 Virt2Phys;
+ //
+ // PXE_VOID Mem_IO(UINT64 UnqId, UINT8 read_write, UINT8 len, UINT64 port,
+ // UINT64 buf_addr);
+ //
+ // UNDI will read or write the device io space using this call back
+ // function. It passes the number of bytes as the len parameter and it
+ // will be either 1,2,4 or 8.
+ //
+ // This field can not be set to zero.
+ //
+ UINT64 Mem_IO;
+ //
+ // PXE_VOID Map_Mem(UINT64 unq_id, UINT64 virtual_addr, UINT32 size,
+ // UINT32 Direction, UINT64 mapped_addr);
+ //
+ // UNDI will pass the virtual address of a buffer, direction of the data
+ // flow from/to the mapped buffer (the constants are defined below)
+ // and a place holder (pointer) for the mapped address.
+ // This call will Map the given address to a physical DMA address and write
+ // the result to the mapped_addr pointer. If there is no need to
+ // map the given address to a lower address (i.e. the given address is
+ // associated with a physical address that is already compatible to be
+ // used with the DMA, it converts the given virtual address to it's
+ // physical address and write that in the mapped address pointer.
+ //
+ // This field can be set to zero if there is no mapping service available
+ //
+ UINT64 Map_Mem;
+
+ //
+ // PXE_VOID UnMap_Mem(UINT64 unq_id, UINT64 virtual_addr, UINT32 size,
+ // UINT32 Direction, UINT64 mapped_addr);
+ //
+ // UNDI will pass the virtual and mapped addresses of a buffer
+ // This call will un map the given address
+ //
+ // This field can be set to zero if there is no unmapping service available
+ //
+ UINT64 UnMap_Mem;
+
+ //
+ // PXE_VOID Sync_Mem(UINT64 unq_id, UINT64 virtual,
+ // UINT32 size, UINT32 Direction, UINT64 mapped_addr);
+ //
+ // UNDI will pass the virtual and mapped addresses of a buffer
+ // This call will synchronize the contents of both the virtual and mapped
+ // buffers for the given Direction.
+ //
+ // This field can be set to zero if there is no service available
+ //
+ UINT64 Sync_Mem;
+
+ //
+ // protocol driver can provide anything for this Unique_ID, UNDI remembers
+ // that as just a 64bit value assocaited to the interface specified by
+ // the ifnum and gives it back as a parameter to all the call-back routines
+ // when calling for that interface!
+ //
+ UINT64 Unique_ID;
+ //
+} PXE_CPB_START_31;
+
+#define TO_AND_FROM_DEVICE 0
+#define FROM_DEVICE 1
+#define TO_DEVICE 2
+
+#define PXE_DELAY_MILLISECOND 1000
+#define PXE_DELAY_SECOND 1000000
+#define PXE_IO_READ 0
+#define PXE_IO_WRITE 1
+#define PXE_MEM_READ 2
+#define PXE_MEM_WRITE 4
+
+typedef struct s_pxe_db_get_init_info {
+ //
+ // Minimum length of locked memory buffer that must be given to
+ // the Initialize command. Giving UNDI more memory will generally
+ // give better performance.
+ //
+ // If MemoryRequired is zero, the UNDI does not need and will not
+ // use system memory to receive and transmit packets.
+ //
+ PXE_UINT32 MemoryRequired;
+
+ //
+ // Maximum frame data length for Tx/Rx excluding the media header.
+ //
+ PXE_UINT32 FrameDataLen;
+
+ //
+ // Supported link speeds are in units of mega bits. Common ethernet
+ // values are 10, 100 and 1000. Unused LinkSpeeds[] entries are zero
+ // filled.
+ //
+ PXE_UINT32 LinkSpeeds[4];
+
+ //
+ // Number of non-volatile storage items.
+ //
+ PXE_UINT32 NvCount;
+
+ //
+ // Width of non-volatile storage item in bytes. 0, 1, 2 or 4
+ //
+ PXE_UINT16 NvWidth;
+
+ //
+ // Media header length. This is the typical media header length for
+ // this UNDI. This information is needed when allocating receive
+ // and transmit buffers.
+ //
+ PXE_UINT16 MediaHeaderLen;
+
+ //
+ // Number of bytes in the NIC hardware (MAC) address.
+ //
+ PXE_UINT16 HWaddrLen;
+
+ //
+ // Maximum number of multicast MAC addresses in the multicast
+ // MAC address filter list.
+ //
+ PXE_UINT16 MCastFilterCnt;
+
+ //
+ // Default number and size of transmit and receive buffers that will
+ // be allocated by the UNDI. If MemoryRequired is non-zero, this
+ // allocation will come out of the memory buffer given to the Initialize
+ // command. If MemoryRequired is zero, this allocation will come out of
+ // memory on the NIC.
+ //
+ PXE_UINT16 TxBufCnt;
+ PXE_UINT16 TxBufSize;
+ PXE_UINT16 RxBufCnt;
+ PXE_UINT16 RxBufSize;
+
+ //
+ // Hardware interface types defined in the Assigned Numbers RFC
+ // and used in DHCP and ARP packets.
+ // See the PXE_IFTYPE typedef and PXE_IFTYPE_xxx macros.
+ //
+ PXE_UINT8 IFtype;
+
+ //
+ // Supported duplex. See PXE_DUPLEX_xxxxx #defines below.
+ //
+ PXE_UINT8 SupportedDuplexModes;
+
+ //
+ // Supported loopback options. See PXE_LOOPBACK_xxxxx #defines below.
+ //
+ PXE_UINT8 SupportedLoopBackModes;
+} PXE_DB_GET_INIT_INFO;
+
+#define PXE_MAX_TXRX_UNIT_ETHER 1500
+
+#define PXE_HWADDR_LEN_ETHER 0x0006
+#define PXE_MAC_HEADER_LEN_ETHER 0x000E
+
+#define PXE_DUPLEX_ENABLE_FULL_SUPPORTED 1
+#define PXE_DUPLEX_FORCE_FULL_SUPPORTED 2
+
+#define PXE_LOOPBACK_INTERNAL_SUPPORTED 1
+#define PXE_LOOPBACK_EXTERNAL_SUPPORTED 2
+
+typedef struct s_pxe_pci_config_info {
+ //
+ // This is the flag field for the PXE_DB_GET_CONFIG_INFO union.
+ // For PCI bus devices, this field is set to PXE_BUSTYPE_PCI.
+ //
+ UINT32 BusType;
+
+ //
+ // This identifies the PCI network device that this UNDI interface
+ // is bound to.
+ //
+ UINT16 Bus;
+ UINT8 Device;
+ UINT8 Function;
+
+ //
+ // This is a copy of the PCI configuration space for this
+ // network device.
+ //
+ union {
+ UINT8 Byte[256];
+ UINT16 Word[128];
+ UINT32 Dword[64];
+ } Config;
+} PXE_PCI_CONFIG_INFO;
+
+typedef struct s_pxe_pcc_config_info {
+ //
+ // This is the flag field for the PXE_DB_GET_CONFIG_INFO union.
+ // For PCC bus devices, this field is set to PXE_BUSTYPE_PCC.
+ //
+ PXE_UINT32 BusType;
+
+ //
+ // This identifies the PCC network device that this UNDI interface
+ // is bound to.
+ //
+ PXE_UINT16 Bus;
+ PXE_UINT8 Device;
+ PXE_UINT8 Function;
+
+ //
+ // This is a copy of the PCC configuration space for this
+ // network device.
+ //
+ union {
+ PXE_UINT8 Byte[256];
+ PXE_UINT16 Word[128];
+ PXE_UINT32 Dword[64];
+ } Config;
+} PXE_PCC_CONFIG_INFO;
+
+typedef union u_pxe_db_get_config_info {
+ PXE_PCI_CONFIG_INFO pci;
+ PXE_PCC_CONFIG_INFO pcc;
+} PXE_DB_GET_CONFIG_INFO;
+
+typedef struct s_pxe_cpb_initialize {
+ //
+ // Address of first (lowest) byte of the memory buffer. This buffer must
+ // be in contiguous physical memory and cannot be swapped out. The UNDI
+ // will be using this for transmit and receive buffering.
+ //
+ PXE_UINT64 MemoryAddr;
+
+ //
+ // MemoryLength must be greater than or equal to MemoryRequired
+ // returned by the Get Init Info command.
+ //
+ PXE_UINT32 MemoryLength;
+
+ //
+ // Desired link speed in Mbit/sec. Common ethernet values are 10, 100
+ // and 1000. Setting a value of zero will auto-detect and/or use the
+ // default link speed (operation depends on UNDI/NIC functionality).
+ //
+ PXE_UINT32 LinkSpeed;
+
+ //
+ // Suggested number and size of receive and transmit buffers to
+ // allocate. If MemoryAddr and MemoryLength are non-zero, this
+ // allocation comes out of the supplied memory buffer. If MemoryAddr
+ // and MemoryLength are zero, this allocation comes out of memory
+ // on the NIC.
+ //
+ // If these fields are set to zero, the UNDI will allocate buffer
+ // counts and sizes as it sees fit.
+ //
+ PXE_UINT16 TxBufCnt;
+ PXE_UINT16 TxBufSize;
+ PXE_UINT16 RxBufCnt;
+ PXE_UINT16 RxBufSize;
+
+ //
+ // The following configuration parameters are optional and must be zero
+ // to use the default values.
+ //
+ PXE_UINT8 DuplexMode;
+
+ PXE_UINT8 LoopBackMode;
+} PXE_CPB_INITIALIZE;
+
+#define PXE_DUPLEX_DEFAULT 0x00
+#define PXE_FORCE_FULL_DUPLEX 0x01
+#define PXE_ENABLE_FULL_DUPLEX 0x02
+#define PXE_FORCE_HALF_DUPLEX 0x04
+#define PXE_DISABLE_FULL_DUPLEX 0x08
+
+#define LOOPBACK_NORMAL 0
+#define LOOPBACK_INTERNAL 1
+#define LOOPBACK_EXTERNAL 2
+
+typedef struct s_pxe_db_initialize {
+ //
+ // Actual amount of memory used from the supplied memory buffer. This
+ // may be less that the amount of memory suppllied and may be zero if
+ // the UNDI and network device do not use external memory buffers.
+ //
+ // Memory used by the UNDI and network device is allocated from the
+ // lowest memory buffer address.
+ //
+ PXE_UINT32 MemoryUsed;
+
+ //
+ // Actual number and size of receive and transmit buffers that were
+ // allocated.
+ //
+ PXE_UINT16 TxBufCnt;
+ PXE_UINT16 TxBufSize;
+ PXE_UINT16 RxBufCnt;
+ PXE_UINT16 RxBufSize;
+} PXE_DB_INITIALIZE;
+
+typedef struct s_pxe_cpb_receive_filters {
+ //
+ // List of multicast MAC addresses. This list, if present, will
+ // replace the existing multicast MAC address filter list.
+ //
+ PXE_MAC_ADDR MCastList[MAX_MCAST_ADDRESS_CNT];
+} PXE_CPB_RECEIVE_FILTERS;
+
+typedef struct s_pxe_db_receive_filters {
+ //
+ // Filtered multicast MAC address list.
+ //
+ PXE_MAC_ADDR MCastList[MAX_MCAST_ADDRESS_CNT];
+} PXE_DB_RECEIVE_FILTERS;
+
+typedef struct s_pxe_cpb_station_address {
+ //
+ // If supplied and supported, the current station MAC address
+ // will be changed.
+ //
+ PXE_MAC_ADDR StationAddr;
+} PXE_CPB_STATION_ADDRESS;
+
+typedef struct s_pxe_dpb_station_address {
+ //
+ // Current station MAC address.
+ //
+ PXE_MAC_ADDR StationAddr;
+
+ //
+ // Station broadcast MAC address.
+ //
+ PXE_MAC_ADDR BroadcastAddr;
+
+ //
+ // Permanent station MAC address.
+ //
+ PXE_MAC_ADDR PermanentAddr;
+} PXE_DB_STATION_ADDRESS;
+
+typedef struct s_pxe_db_statistics {
+ //
+ // Bit field identifying what statistic data is collected by the
+ // UNDI/NIC.
+ // If bit 0x00 is set, Data[0x00] is collected.
+ // If bit 0x01 is set, Data[0x01] is collected.
+ // If bit 0x20 is set, Data[0x20] is collected.
+ // If bit 0x21 is set, Data[0x21] is collected.
+ // Etc.
+ //
+ PXE_UINT64 Supported;
+
+ //
+ // Statistic data.
+ //
+ PXE_UINT64 Data[64];
+} PXE_DB_STATISTICS;
+
+//
+// Total number of frames received. Includes frames with errors and
+// dropped frames.
+//
+#define PXE_STATISTICS_RX_TOTAL_FRAMES 0x00
+
+//
+// Number of valid frames received and copied into receive buffers.
+//
+#define PXE_STATISTICS_RX_GOOD_FRAMES 0x01
+
+//
+// Number of frames below the minimum length for the media.
+// This would be <64 for ethernet.
+//
+#define PXE_STATISTICS_RX_UNDERSIZE_FRAMES 0x02
+
+//
+// Number of frames longer than the maxminum length for the
+// media. This would be >1500 for ethernet.
+//
+#define PXE_STATISTICS_RX_OVERSIZE_FRAMES 0x03
+
+//
+// Valid frames that were dropped because receive buffers were full.
+//
+#define PXE_STATISTICS_RX_DROPPED_FRAMES 0x04
+
+//
+// Number of valid unicast frames received and not dropped.
+//
+#define PXE_STATISTICS_RX_UNICAST_FRAMES 0x05
+
+//
+// Number of valid broadcast frames received and not dropped.
+//
+#define PXE_STATISTICS_RX_BROADCAST_FRAMES 0x06
+
+//
+// Number of valid mutlicast frames received and not dropped.
+//
+#define PXE_STATISTICS_RX_MULTICAST_FRAMES 0x07
+
+//
+// Number of frames w/ CRC or alignment errors.
+//
+#define PXE_STATISTICS_RX_CRC_ERROR_FRAMES 0x08
+
+//
+// Total number of bytes received. Includes frames with errors
+// and dropped frames.
+//
+#define PXE_STATISTICS_RX_TOTAL_BYTES 0x09
+
+//
+// Transmit statistics.
+//
+#define PXE_STATISTICS_TX_TOTAL_FRAMES 0x0A
+#define PXE_STATISTICS_TX_GOOD_FRAMES 0x0B
+#define PXE_STATISTICS_TX_UNDERSIZE_FRAMES 0x0C
+#define PXE_STATISTICS_TX_OVERSIZE_FRAMES 0x0D
+#define PXE_STATISTICS_TX_DROPPED_FRAMES 0x0E
+#define PXE_STATISTICS_TX_UNICAST_FRAMES 0x0F
+#define PXE_STATISTICS_TX_BROADCAST_FRAMES 0x10
+#define PXE_STATISTICS_TX_MULTICAST_FRAMES 0x11
+#define PXE_STATISTICS_TX_CRC_ERROR_FRAMES 0x12
+#define PXE_STATISTICS_TX_TOTAL_BYTES 0x13
+
+//
+// Number of collisions detection on this subnet.
+//
+#define PXE_STATISTICS_COLLISIONS 0x14
+
+//
+// Number of frames destined for unsupported protocol.
+//
+#define PXE_STATISTICS_UNSUPPORTED_PROTOCOL 0x15
+
+typedef struct s_pxe_cpb_mcast_ip_to_mac {
+ //
+ // Multicast IP address to be converted to multicast MAC address.
+ //
+ PXE_IP_ADDR IP;
+} PXE_CPB_MCAST_IP_TO_MAC;
+
+typedef struct s_pxe_db_mcast_ip_to_mac {
+ //
+ // Multicast MAC address.
+ //
+ PXE_MAC_ADDR MAC;
+} PXE_DB_MCAST_IP_TO_MAC;
+
+typedef struct s_pxe_cpb_nvdata_sparse {
+ //
+ // NvData item list. Only items in this list will be updated.
+ //
+ struct {
+ //
+ // Non-volatile storage address to be changed.
+ //
+ PXE_UINT32 Addr;
+
+ //
+ // Data item to write into above storage address.
+ //
+ union {
+ PXE_UINT8 Byte;
+ PXE_UINT16 Word;
+ PXE_UINT32 Dword;
+ } Data;
+ } Item[MAX_EEPROM_LEN];
+}
+PXE_CPB_NVDATA_SPARSE;
+
+//
+// When using bulk update, the size of the CPB structure must be
+// the same size as the non-volatile NIC storage.
+//
+typedef union u_pxe_cpb_nvdata_bulk {
+ //
+ // Array of byte-wide data items.
+ //
+ PXE_UINT8 Byte[MAX_EEPROM_LEN << 2];
+
+ //
+ // Array of word-wide data items.
+ //
+ PXE_UINT16 Word[MAX_EEPROM_LEN << 1];
+
+ //
+ // Array of dword-wide data items.
+ //
+ PXE_UINT32 Dword[MAX_EEPROM_LEN];
+} PXE_CPB_NVDATA_BULK;
+
+typedef struct s_pxe_db_nvdata {
+ //
+ // Arrays of data items from non-volatile storage.
+ //
+ union {
+ //
+ // Array of byte-wide data items.
+ //
+ PXE_UINT8 Byte[MAX_EEPROM_LEN << 2];
+
+ //
+ // Array of word-wide data items.
+ //
+ PXE_UINT16 Word[MAX_EEPROM_LEN << 1];
+
+ //
+ // Array of dword-wide data items.
+ //
+ PXE_UINT32 Dword[MAX_EEPROM_LEN];
+ } Data;
+} PXE_DB_NVDATA;
+
+typedef struct s_pxe_db_get_status {
+ //
+ // Length of next receive frame (header + data). If this is zero,
+ // there is no next receive frame available.
+ //
+ PXE_UINT32 RxFrameLen;
+
+ //
+ // Reserved, set to zero.
+ //
+ PXE_UINT32 reserved;
+
+ //
+ // Addresses of transmitted buffers that need to be recycled.
+ //
+ PXE_UINT64 TxBuffer[MAX_XMIT_BUFFERS];
+} PXE_DB_GET_STATUS;
+
+typedef struct s_pxe_cpb_fill_header {
+ //
+ // Source and destination MAC addresses. These will be copied into
+ // the media header without doing byte swapping.
+ //
+ PXE_MAC_ADDR SrcAddr;
+ PXE_MAC_ADDR DestAddr;
+
+ //
+ // Address of first byte of media header. The first byte of packet data
+ // follows the last byte of the media header.
+ //
+ PXE_UINT64 MediaHeader;
+
+ //
+ // Length of packet data in bytes (not including the media header).
+ //
+ PXE_UINT32 PacketLen;
+
+ //
+ // Protocol type. This will be copied into the media header without
+ // doing byte swapping. Protocol type numbers can be obtained from
+ // the Assigned Numbers RFC 1700.
+ //
+ PXE_UINT16 Protocol;
+
+ //
+ // Length of the media header in bytes.
+ //
+ PXE_UINT16 MediaHeaderLen;
+} PXE_CPB_FILL_HEADER;
+
+#define PXE_PROTOCOL_ETHERNET_IP 0x0800
+#define PXE_PROTOCOL_ETHERNET_ARP 0x0806
+#define MAX_XMIT_FRAGMENTS 16
+
+typedef struct s_pxe_cpb_fill_header_fragmented {
+ //
+ // Source and destination MAC addresses. These will be copied into
+ // the media header without doing byte swapping.
+ //
+ PXE_MAC_ADDR SrcAddr;
+ PXE_MAC_ADDR DestAddr;
+
+ //
+ // Length of packet data in bytes (not including the media header).
+ //
+ PXE_UINT32 PacketLen;
+
+ //
+ // Protocol type. This will be copied into the media header without
+ // doing byte swapping. Protocol type numbers can be obtained from
+ // the Assigned Numbers RFC 1700.
+ //
+ PXE_MEDIA_PROTOCOL Protocol;
+
+ //
+ // Length of the media header in bytes.
+ //
+ PXE_UINT16 MediaHeaderLen;
+
+ //
+ // Number of packet fragment descriptors.
+ //
+ PXE_UINT16 FragCnt;
+
+ //
+ // Reserved, must be set to zero.
+ //
+ PXE_UINT16 reserved;
+
+ //
+ // Array of packet fragment descriptors. The first byte of the media
+ // header is the first byte of the first fragment.
+ //
+ struct {
+ //
+ // Address of this packet fragment.
+ //
+ PXE_UINT64 FragAddr;
+
+ //
+ // Length of this packet fragment.
+ //
+ PXE_UINT32 FragLen;
+
+ //
+ // Reserved, must be set to zero.
+ //
+ PXE_UINT32 reserved;
+ } FragDesc[MAX_XMIT_FRAGMENTS];
+}
+PXE_CPB_FILL_HEADER_FRAGMENTED;
+
+typedef struct s_pxe_cpb_transmit {
+ //
+ // Address of first byte of frame buffer. This is also the first byte
+ // of the media header.
+ //
+ PXE_UINT64 FrameAddr;
+
+ //
+ // Length of the data portion of the frame buffer in bytes. Do not
+ // include the length of the media header.
+ //
+ PXE_UINT32 DataLen;
+
+ //
+ // Length of the media header in bytes.
+ //
+ PXE_UINT16 MediaheaderLen;
+
+ //
+ // Reserved, must be zero.
+ //
+ PXE_UINT16 reserved;
+} PXE_CPB_TRANSMIT;
+
+typedef struct s_pxe_cpb_transmit_fragments {
+ //
+ // Length of packet data in bytes (not including the media header).
+ //
+ PXE_UINT32 FrameLen;
+
+ //
+ // Length of the media header in bytes.
+ //
+ PXE_UINT16 MediaheaderLen;
+
+ //
+ // Number of packet fragment descriptors.
+ //
+ PXE_UINT16 FragCnt;
+
+ //
+ // Array of frame fragment descriptors. The first byte of the first
+ // fragment is also the first byte of the media header.
+ //
+ struct {
+ //
+ // Address of this frame fragment.
+ //
+ PXE_UINT64 FragAddr;
+
+ //
+ // Length of this frame fragment.
+ //
+ PXE_UINT32 FragLen;
+
+ //
+ // Reserved, must be set to zero.
+ //
+ PXE_UINT32 reserved;
+ } FragDesc[MAX_XMIT_FRAGMENTS];
+}
+PXE_CPB_TRANSMIT_FRAGMENTS;
+
+typedef struct s_pxe_cpb_receive {
+ //
+ // Address of first byte of receive buffer. This is also the first byte
+ // of the frame header.
+ //
+ PXE_UINT64 BufferAddr;
+
+ //
+ // Length of receive buffer. This must be large enough to hold the
+ // received frame (media header + data). If the length of smaller than
+ // the received frame, data will be lost.
+ //
+ PXE_UINT32 BufferLen;
+
+ //
+ // Reserved, must be set to zero.
+ //
+ PXE_UINT32 reserved;
+} PXE_CPB_RECEIVE;
+
+typedef struct s_pxe_db_receive {
+ //
+ // Source and destination MAC addresses from media header.
+ //
+ PXE_MAC_ADDR SrcAddr;
+ PXE_MAC_ADDR DestAddr;
+
+ //
+ // Length of received frame. May be larger than receive buffer size.
+ // The receive buffer will not be overwritten. This is how to tell
+ // if data was lost because the receive buffer was too small.
+ //
+ PXE_UINT32 FrameLen;
+
+ //
+ // Protocol type from media header.
+ //
+ PXE_MEDIA_PROTOCOL Protocol;
+
+ //
+ // Length of media header in received frame.
+ //
+ PXE_UINT16 MediaHeaderLen;
+
+ //
+ // Type of receive frame.
+ //
+ PXE_FRAME_TYPE Type;
+
+ //
+ // Reserved, must be zero.
+ //
+ PXE_UINT8 reserved[7];
+
+} PXE_DB_RECEIVE;
+
+//
+// Packet definitions
+//
+typedef struct {
+ UINT8 BootpOpcode;
+ UINT8 BootpHwType;
+ UINT8 BootpHwAddrLen;
+ UINT8 BootpGateHops;
+ UINT32 BootpIdent;
+ UINT16 BootpSeconds;
+ UINT16 BootpFlags;
+ UINT8 BootpCiAddr[4];
+ UINT8 BootpYiAddr[4];
+ UINT8 BootpSiAddr[4];
+ UINT8 BootpGiAddr[4];
+ UINT8 BootpHwAddr[16];
+ UINT8 BootpSrvName[64];
+ UINT8 BootpBootFile[128];
+ UINT32 DhcpMagik;
+ UINT8 DhcpOptions[56];
+} EFI_PXE_BASE_CODE_DHCPV4_PACKET;
+
+typedef union {
+ UINT8 Raw[1472];
+ EFI_PXE_BASE_CODE_DHCPV4_PACKET Dhcpv4;
+
+ //
+ // EFI_PXE_BASE_CODE_DHCPV6_PACKET Dhcpv6;
+ //
+} EFI_PXE_BASE_CODE_PACKET;
+
+
+
+#pragma pack()
+
+#endif
diff --git a/gpxe/src/include/gpxe/efi/Uefi/UefiSpec.h b/gpxe/src/include/gpxe/efi/Uefi/UefiSpec.h
new file mode 100644
index 00000000..54c3ace7
--- /dev/null
+++ b/gpxe/src/include/gpxe/efi/Uefi/UefiSpec.h
@@ -0,0 +1,1780 @@
+/** @file
+ Include file that supportes UEFI.
+
+ This include file must only contain things defined in the UEFI 2.0 specification.
+ If a code construct is defined in the UEFI 2.0 specification it must be included
+ by this include file.
+
+ Copyright (c) 2006 - 2007, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __UEFI_SPEC_H__
+#define __UEFI_SPEC_H__
+
+#include <gpxe/efi/Uefi/UefiMultiPhase.h>
+
+#include <gpxe/efi/Protocol/DevicePath.h>
+#include <gpxe/efi/Protocol/SimpleTextIn.h>
+#include <gpxe/efi/Protocol/SimpleTextOut.h>
+
+///
+/// Enumeration of memory allocation.
+///
+typedef enum {
+ AllocateAnyPages,
+ AllocateMaxAddress,
+ AllocateAddress,
+ MaxAllocateType
+} EFI_ALLOCATE_TYPE;
+
+//
+// Bit definitions for EFI_TIME.Daylight
+//
+#define EFI_TIME_ADJUST_DAYLIGHT 0x01
+#define EFI_TIME_IN_DAYLIGHT 0x02
+
+///
+/// Value definition for EFI_TIME.TimeZone
+///
+#define EFI_UNSPECIFIED_TIMEZONE 0x07FF
+
+//
+// possible caching types for the memory range
+//
+#define EFI_MEMORY_UC 0x0000000000000001ULL
+#define EFI_MEMORY_WC 0x0000000000000002ULL
+#define EFI_MEMORY_WT 0x0000000000000004ULL
+#define EFI_MEMORY_WB 0x0000000000000008ULL
+#define EFI_MEMORY_UCE 0x0000000000000010ULL
+
+//
+// physical memory protection on range
+//
+#define EFI_MEMORY_WP 0x0000000000001000ULL
+#define EFI_MEMORY_RP 0x0000000000002000ULL
+#define EFI_MEMORY_XP 0x0000000000004000ULL
+
+///
+/// range requires a runtime mapping
+///
+#define EFI_MEMORY_RUNTIME 0x8000000000000000ULL
+
+#define EFI_MEMORY_DESCRIPTOR_VERSION 1
+typedef struct {
+ UINT32 Type;
+ EFI_PHYSICAL_ADDRESS PhysicalStart;
+ EFI_VIRTUAL_ADDRESS VirtualStart;
+ UINT64 NumberOfPages;
+ UINT64 Attribute;
+} EFI_MEMORY_DESCRIPTOR;
+
+///
+/// Build macros to find next EFI_MEMORY_DESCRIPTOR.
+///
+#define NextMemoryDescriptor(_Ptr, _Size) ((EFI_MEMORY_DESCRIPTOR *) (((UINT8 *) (_Ptr)) + (_Size)))
+#define NEXT_MEMORY_DESCRIPTOR(_Ptr, _Size) NextMemoryDescriptor (_Ptr, _Size)
+
+///
+/// Declare forward referenced data structures
+///
+typedef struct _EFI_SYSTEM_TABLE EFI_SYSTEM_TABLE;
+
+/**
+ Allocates memory pages from the system.
+
+ @param Type The type of allocation to perform.
+ @param MemoryType The type of memory to allocate.
+ @param Pages The number of contiguous 4 KB pages to allocate.
+ @param Memory Pointer to a physical address. On input, the way in which the address is
+ used depends on the value of Type.
+
+ @retval EFI_SUCCESS The requested pages were allocated.
+ @retval EFI_INVALID_PARAMETER 1) Type is not AllocateAnyPages or
+ AllocateMaxAddress or AllocateAddress.
+ 2) MemoryType is in the range
+ EfiMaxMemoryType..0x7FFFFFFF.
+ @retval EFI_OUT_OF_RESOURCES The pages could not be allocated.
+ @retval EFI_NOT_FOUND The requested pages could not be found.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_ALLOCATE_PAGES)(
+ IN EFI_ALLOCATE_TYPE Type,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN Pages,
+ IN OUT EFI_PHYSICAL_ADDRESS *Memory
+ );
+
+/**
+ Frees memory pages.
+
+ @param Memory The base physical address of the pages to be freed.
+ @param Pages The number of contiguous 4 KB pages to free.
+
+ @retval EFI_SUCCESS The requested pages were freed.
+ @retval EFI_INVALID_PARAMETER Memory is not a page-aligned address or Pages is invalid.
+ @retval EFI_NOT_FOUND The requested memory pages were not allocated with
+ AllocatePages().
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_FREE_PAGES)(
+ IN EFI_PHYSICAL_ADDRESS Memory,
+ IN UINTN Pages
+ );
+
+/**
+ Returns the current memory map.
+
+ @param MemoryMapSize A pointer to the size, in bytes, of the MemoryMap buffer.
+ @param MemoryMap A pointer to the buffer in which firmware places the current memory
+ map.
+ @param MapKey A pointer to the location in which firmware returns the key for the
+ current memory map.
+ @param DescriptorSize A pointer to the location in which firmware returns the size, in bytes, of
+ an individual EFI_MEMORY_DESCRIPTOR.
+ @param DescriptorVersion A pointer to the location in which firmware returns the version number
+ associated with the EFI_MEMORY_DESCRIPTOR.
+
+ @retval EFI_SUCCESS The memory map was returned in the MemoryMap buffer.
+ @retval EFI_BUFFER_TOO_SMALL The MemoryMap buffer was too small. The current buffer size
+ needed to hold the memory map is returned in MemoryMapSize.
+ @retval EFI_INVALID_PARAMETER 1) MemoryMapSize is NULL.
+ 2) The MemoryMap buffer is not too small and MemoryMap is
+ NULL.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_GET_MEMORY_MAP)(
+ IN OUT UINTN *MemoryMapSize,
+ IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
+ OUT UINTN *MapKey,
+ OUT UINTN *DescriptorSize,
+ OUT UINT32 *DescriptorVersion
+ );
+
+/**
+ Allocates pool memory.
+
+ @param PoolType The type of pool to allocate.
+ @param Size The number of bytes to allocate from the pool.
+ @param Buffer A pointer to a pointer to the allocated buffer if the call succeeds;
+ undefined otherwise.
+
+ @retval EFI_SUCCESS The requested number of bytes was allocated.
+ @retval EFI_OUT_OF_RESOURCES The pool requested could not be allocated.
+ @retval EFI_INVALID_PARAMETER PoolType was invalid.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_ALLOCATE_POOL)(
+ IN EFI_MEMORY_TYPE PoolType,
+ IN UINTN Size,
+ OUT VOID **Buffer
+ );
+
+/**
+ Returns pool memory to the system.
+
+ @param Buffer Pointer to the buffer to free.
+
+ @retval EFI_SUCCESS The memory was returned to the system.
+ @retval EFI_INVALID_PARAMETER Buffer was invalid.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_FREE_POOL)(
+ IN VOID *Buffer
+ );
+
+/**
+ Changes the runtime addressing mode of EFI firmware from physical to virtual.
+
+ @param MemoryMapSize The size in bytes of VirtualMap.
+ @param DescriptorSize The size in bytes of an entry in the VirtualMap.
+ @param DescriptorVersion The version of the structure entries in VirtualMap.
+ @param VirtualMap An array of memory descriptors which contain new virtual
+ address mapping information for all runtime ranges.
+
+ @retval EFI_SUCCESS The virtual address map has been applied.
+ @retval EFI_UNSUPPORTED EFI firmware is not at runtime, or the EFI firmware is already in
+ virtual address mapped mode.
+ @retval EFI_INVALID_PARAMETER DescriptorSize or DescriptorVersion is invalid.
+ @retval EFI_NO_MAPPING A virtual address was not supplied for a range in the memory
+ map that requires a mapping.
+ @retval EFI_NOT_FOUND A virtual address was supplied for an address that is not found
+ in the memory map.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SET_VIRTUAL_ADDRESS_MAP)(
+ IN UINTN MemoryMapSize,
+ IN UINTN DescriptorSize,
+ IN UINT32 DescriptorVersion,
+ IN EFI_MEMORY_DESCRIPTOR *VirtualMap
+ );
+
+/**
+ Connects one or more drivers to a controller.
+
+ @param ControllerHandle The handle of the controller to which driver(s) are to be connected.
+ @param DriverImageHandle A pointer to an ordered list handles that support the
+ EFI_DRIVER_BINDING_PROTOCOL.
+ @param RemainingDevicePath A pointer to the device path that specifies a child of the
+ controller specified by ControllerHandle.
+ @param Recursive If TRUE, then ConnectController() is called recursively
+ until the entire tree of controllers below the controller specified
+ by ControllerHandle have been created. If FALSE, then
+ the tree of controllers is only expanded one level.
+
+ @retval EFI_SUCCESS 1) One or more drivers were connected to ControllerHandle.
+ 2) No drivers were connected to ControllerHandle, but
+ RemainingDevicePath is not NULL, and it is an End Device
+ Path Node.
+ @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.
+ @retval EFI_NOT_FOUND 1) There are no EFI_DRIVER_BINDING_PROTOCOL instances
+ present in the system.
+ 2) No drivers were connected to ControllerHandle.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_CONNECT_CONTROLLER)(
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE *DriverImageHandle, OPTIONAL
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath, OPTIONAL
+ IN BOOLEAN Recursive
+ );
+
+/**
+ Disconnects one or more drivers from a controller.
+
+ @param ControllerHandle The handle of the controller from which driver(s) are to be disconnected.
+ @param DriverImageHandle The driver to disconnect from ControllerHandle.
+ @param ChildHandle The handle of the child to destroy.
+
+ @retval EFI_SUCCESS 1) One or more drivers were disconnected from the controller.
+ 2) On entry, no drivers are managing ControllerHandle.
+ 3) DriverImageHandle is not NULL, and on entry
+ DriverImageHandle is not managing ControllerHandle.
+
+ @retval EFI_INVALID_PARAMETER One ore more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources available to disconnect any drivers from
+ ControllerHandle.
+ @retval EFI_DEVICE_ERROR The controller could not be disconnected because of a device error.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_DISCONNECT_CONTROLLER)(
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE DriverImageHandle, OPTIONAL
+ IN EFI_HANDLE ChildHandle OPTIONAL
+ );
+
+
+
+//
+// ConvertPointer DebugDisposition type.
+//
+#define EFI_OPTIONAL_PTR 0x00000001
+#define EFI_OPTIONAL_POINTER EFI_OPTIONAL_PTR
+
+/**
+ Determines the new virtual address that is to be used on subsequent memory accesses.
+
+ @param DebugDisposition Supplies type information for the pointer being converted.
+ @param Address A pointer to a pointer that is to be fixed to be the value needed
+ for the new virtual address mappings being applied.
+
+ @retval EFI_SUCCESS The pointer pointed to by Address was modified.
+ @retval EFI_INVALID_PARAMETER 1) Address is NULL.
+ 2) *Address is NULL and DebugDisposition does
+ not have the EFI_OPTIONAL_PTR bit set.
+ @retval EFI_NOT_FOUND The pointer pointed to by Address was not found to be part
+ of the current memory map. This is normally fatal.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_CONVERT_POINTER)(
+ IN UINTN DebugDisposition,
+ IN OUT VOID **Address
+ );
+
+
+//
+// These types can be ORed together as needed - for example,
+// EVT_TIMER might be Ored with EVT_NOTIFY_WAIT or
+// EVT_NOTIFY_SIGNAL.
+//
+#define EVT_TIMER 0x80000000
+#define EVT_RUNTIME 0x40000000
+#define EVT_NOTIFY_WAIT 0x00000100
+#define EVT_NOTIFY_SIGNAL 0x00000200
+
+#define EVT_SIGNAL_EXIT_BOOT_SERVICES 0x00000201
+#define EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE 0x60000202
+
+//
+// The event's NotifyContext pointer points to a runtime memory
+// address.
+// The event is deprecated in UEFI2.0 and later specifications.
+//
+#define EVT_RUNTIME_CONTEXT 0x20000000
+
+
+/**
+ Invoke a notification event
+
+ @param Event Event whose notification function is being invoked.
+ @param Context Pointer to the notification function's context,
+ which is implementation-dependent.
+
+**/
+typedef
+VOID
+(EFIAPI *EFI_EVENT_NOTIFY)(
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+/**
+ Creates an event.
+
+ @param Type The type of event to create and its mode and attributes.
+ @param NotifyTpl Pointer to the notification function's context.
+ @param NotifyFunction Pointer to the event's notification function, if any.
+ @param NotifyContext Pointer to the notification function's context; corresponds to parameter
+ Context in the notification function.
+ @param Event Pointer to the newly created event if the call succeeds; undefined
+ otherwise.
+
+ @retval EFI_SUCCESS The event structure was created.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The event could not be allocated.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_CREATE_EVENT)(
+ IN UINT32 Type,
+ IN EFI_TPL NotifyTpl,
+ IN EFI_EVENT_NOTIFY NotifyFunction,
+ IN VOID *NotifyContext,
+ OUT EFI_EVENT *Event
+ );
+
+/**
+ Creates an event in a group.
+
+ @param Type The type of event to create and its mode and attributes.
+ @param NotifyTpl Pointer to the notification function's context.
+ @param NotifyFunction Pointer to the event's notification function, if any.
+ @param NotifyContext Pointer to the notification function's context; corresponds to parameter
+ Context in the notification function.
+ @param EventGroup Pointer to the unique identifier of the group to which this event belongs.
+ @param Event Pointer to the newly created event if the call succeeds; undefined
+ otherwise.
+
+ @retval EFI_SUCCESS The event structure was created.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The event could not be allocated.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_CREATE_EVENT_EX)(
+ IN UINT32 Type,
+ IN EFI_TPL NotifyTpl OPTIONAL,
+ IN EFI_EVENT_NOTIFY NotifyFunction OPTIONAL,
+ IN CONST VOID *NotifyContext OPTIONAL,
+ IN CONST EFI_GUID *EventGroup OPTIONAL,
+ OUT EFI_EVENT *Event
+ );
+
+typedef enum {
+ TimerCancel,
+ TimerPeriodic,
+ TimerRelative
+} EFI_TIMER_DELAY;
+
+/**
+ Sets the type of timer and the trigger time for a timer event.
+
+ @param Event The timer event that is to be signaled at the specified time.
+ @param Type The type of time that is specified in TriggerTime.
+ @param TriggerTime The number of 100ns units until the timer expires.
+
+ @retval EFI_SUCCESS The event has been set to be signaled at the requested time.
+ @retval EFI_INVALID_PARAMETER Event or Type is not valid.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SET_TIMER)(
+ IN EFI_EVENT Event,
+ IN EFI_TIMER_DELAY Type,
+ IN UINT64 TriggerTime
+ );
+
+/**
+ Signals an event.
+
+ @param Event The event to signal.
+
+ @retval EFI_SUCCESS The event has been signaled.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SIGNAL_EVENT)(
+ IN EFI_EVENT Event
+ );
+
+/**
+ Stops execution until an event is signaled.
+
+ @param NumberOfEvents The number of events in the Event array.
+ @param Event An array of EFI_EVENT.
+ @param Index Pointer to the index of the event which satisfied the wait condition.
+
+ @retval EFI_SUCCESS The event indicated by Index was signaled.
+ @retval EFI_INVALID_PARAMETER 1) NumberOfEvents is 0.
+ 2) The event indicated by Index is of type
+ EVT_NOTIFY_SIGNAL.
+ @retval EFI_UNSUPPORTED The current TPL is not TPL_APPLICATION.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_WAIT_FOR_EVENT)(
+ IN UINTN NumberOfEvents,
+ IN EFI_EVENT *Event,
+ OUT UINTN *Index
+ );
+
+/**
+ Closes an event.
+
+ @param Event The event to close.
+
+ @retval EFI_SUCCESS The event has been closed.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_CLOSE_EVENT)(
+ IN EFI_EVENT Event
+ );
+
+/**
+ Checks whether an event is in the signaled state.
+
+ @param Event The event to check.
+
+ @retval EFI_SUCCESS The event is in the signaled state.
+ @retval EFI_NOT_READY The event is not in the signaled state.
+ @retval EFI_INVALID_PARAMETER Event is of type EVT_NOTIFY_SIGNAL.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_CHECK_EVENT)(
+ IN EFI_EVENT Event
+ );
+
+
+//
+// Task priority level (name defined in spec).
+//
+#define TPL_APPLICATION 4
+#define TPL_CALLBACK 8
+#define TPL_NOTIFY 16
+#define TPL_HIGH_LEVEL 31
+
+
+/**
+ Raises a task's priority level and returns its previous level.
+
+ @param NewTpl The new task priority level.
+
+ @retval Previous task priority level
+
+**/
+typedef
+EFI_TPL
+(EFIAPI *EFI_RAISE_TPL)(
+ IN EFI_TPL NewTpl
+ );
+
+/**
+ Restores a task's priority level to its previous value.
+
+ @param OldTpl The previous task priority level to restore
+
+**/
+typedef
+VOID
+(EFIAPI *EFI_RESTORE_TPL)(
+ IN EFI_TPL OldTpl
+ );
+
+/**
+ Returns the value of a variable.
+
+ @param VariableName A Null-terminated Unicode string that is the name of the
+ vendor's variable.
+ @param VendorGuid A unique identifier for the vendor.
+ @param Attributes If not NULL, a pointer to the memory location to return the
+ attributes bitmask for the variable.
+ @param DataSize On input, the size in bytes of the return Data buffer.
+ On output the size of data returned in Data.
+ @param Data The buffer to return the contents of the variable.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_NOT_FOUND The variable was not found.
+ @retval EFI_BUFFER_TOO_SMALL The DataSize is too small for the result.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_DEVICE_ERROR The variable could not be retrieved due to a hardware error.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_GET_VARIABLE)(
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ OUT UINT32 *Attributes, OPTIONAL
+ IN OUT UINTN *DataSize,
+ OUT VOID *Data
+ );
+
+/**
+ Enumerates the current variable names.
+
+ @param VariableNameSize The size of the VariableName buffer.
+ @param VariableName On input, supplies the last VariableName that was returned
+ by GetNextVariableName(). On output, returns the Nullterminated
+ Unicode string of the current variable.
+ @param VendorGuid On input, supplies the last VendorGuid that was returned by
+ GetNextVariableName(). On output, returns the
+ VendorGuid of the current variable.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_NOT_FOUND The next variable was not found.
+ @retval EFI_BUFFER_TOO_SMALL The VariableNameSize is too small for the result.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_DEVICE_ERROR The variable could not be retrieved due to a hardware error.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_GET_NEXT_VARIABLE_NAME)(
+ IN OUT UINTN *VariableNameSize,
+ IN OUT CHAR16 *VariableName,
+ IN OUT EFI_GUID *VendorGuid
+ );
+
+/**
+ Sets the value of a variable.
+
+ @param VariableName A Null-terminated Unicode string that is the name of the
+ vendor's variable.
+ @param VendorGuid A unique identifier for the vendor.
+ @param Attributes Attributes bitmask to set for the variable.
+ @param DataSize The size in bytes of the Data buffer.
+ @param Data The contents for the variable.
+
+ @retval EFI_SUCCESS The firmware has successfully stored the variable and its data as
+ defined by the Attributes.
+ @retval EFI_WRITE_PROTECTED The variable in question is read-only.
+ @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the variable and its data.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_DEVICE_ERROR The variable could not be retrieved due to a hardware error.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SET_VARIABLE)(
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN UINT32 Attributes,
+ IN UINTN DataSize,
+ IN VOID *Data
+ );
+
+
+//
+// This provides the capabilities of the
+// real time clock device as exposed through the EFI interfaces.
+//
+typedef struct {
+ UINT32 Resolution;
+ UINT32 Accuracy;
+ BOOLEAN SetsToZero;
+} EFI_TIME_CAPABILITIES;
+
+/**
+ Returns the current time and date information, and the time-keeping capabilities
+ of the hardware platform.
+
+ @param Time A pointer to storage to receive a snapshot of the current time.
+ @param Capabilities An optional pointer to a buffer to receive the real time clock
+ device's capabilities.
+
+ @retval EFI_SUCCESS The operation completed successfully.
+ @retval EFI_INVALID_PARAMETER Time is NULL.
+ @retval EFI_DEVICE_ERROR The time could not be retrieved due to hardware error.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_GET_TIME)(
+ OUT EFI_TIME *Time,
+ OUT EFI_TIME_CAPABILITIES *Capabilities OPTIONAL
+ );
+
+/**
+ Sets the current local time and date information.
+
+ @param Time A pointer to the current time.
+
+ @retval EFI_SUCCESS The operation completed successfully.
+ @retval EFI_INVALID_PARAMETER A time field is out of range.
+ @retval EFI_DEVICE_ERROR The time could not be set due due to hardware error.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SET_TIME)(
+ IN EFI_TIME *Time
+ );
+
+/**
+ Returns the current wakeup alarm clock setting.
+
+ @param Enabled Indicates if the alarm is currently enabled or disabled.
+ @param Pending Indicates if the alarm signal is pending and requires acknowledgement.
+ @param Time The current alarm setting.
+
+ @retval EFI_SUCCESS The alarm settings were returned.
+ @retval EFI_INVALID_PARAMETER Any parameter is NULL.
+ @retval EFI_DEVICE_ERROR The wakeup time could not be retrieved due to a hardware error.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_GET_WAKEUP_TIME)(
+ OUT BOOLEAN *Enabled,
+ OUT BOOLEAN *Pending,
+ OUT EFI_TIME *Time
+ );
+
+/**
+ Sets the system wakeup alarm clock time.
+
+ @param Enabled Enable or disable the wakeup alarm.
+ @param Time If Enable is TRUE, the time to set the wakeup alarm for.
+
+ @retval EFI_SUCCESS If Enable is TRUE, then the wakeup alarm was enabled. If
+ Enable is FALSE, then the wakeup alarm was disabled.
+ @retval EFI_INVALID_PARAMETER A time field is out of range.
+ @retval EFI_DEVICE_ERROR The wakeup time could not be set due to a hardware error.
+ @retval EFI_UNSUPPORTED A wakeup timer is not supported on this platform.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SET_WAKEUP_TIME)(
+ IN BOOLEAN Enable,
+ IN EFI_TIME *Time OPTIONAL
+ );
+
+/**
+ This is the declaration of an EFI image entry point. This can be the entry point to an application
+ written to this specification, an EFI boot service driver, or an EFI runtime driver.
+
+ @param ImageHandle Handle that identifies the loaded image.
+ @param SystemTable System Table for this image.
+
+ @retval EFI_SUCCESS The operation completed successfully.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_IMAGE_ENTRY_POINT)(
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ );
+
+/**
+ Loads an EFI image into memory.
+
+ @param BootPolicy If TRUE, indicates that the request originates from the boot
+ manager, and that the boot manager is attempting to load
+ FilePath as a boot selection. Ignored if SourceBuffer is
+ not NULL.
+ @param ParentImageHandle The caller's image handle.
+ @param FilePath The DeviceHandle specific file path from which the image is
+ loaded.
+ @param SourceBuffer If not NULL, a pointer to the memory location containing a copy
+ of the image to be loaded.
+ @param SourceSize The size in bytes of SourceBuffer.
+ @param ImageHandle Pointer to the returned image handle that is created when the
+ image is successfully loaded.
+
+ @retval EFI_SUCCESS Image was loaded into memory correctly.
+ @retval EFI_NOT_FOUND Both SourceBuffer and FilePath are NULL.
+ @retval EFI_INVALID_PARAMETER One or more parametes are invalid.
+ @retval EFI_UNSUPPORTED The image type is not supported.
+ @retval EFI_OUT_OF_RESOURCES Image was not loaded due to insufficient resources.
+ @retval EFI_LOAD_ERROR Image was not loaded because the image format was corrupt or not
+ understood.
+ @retval EFI_DEVICE_ERROR Image was not loaded because the device returned a read error.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_IMAGE_LOAD)(
+ IN BOOLEAN BootPolicy,
+ IN EFI_HANDLE ParentImageHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ IN VOID *SourceBuffer OPTIONAL,
+ IN UINTN SourceSize,
+ OUT EFI_HANDLE *ImageHandle
+ );
+
+/**
+ Transfers control to a loaded image's entry point.
+
+ @param ImageHandle Handle of image to be started.
+ @param ExitDataSize Pointer to the size, in bytes, of ExitData.
+ @param ExitData Pointer to a pointer to a data buffer that includes a Null-terminated
+ Unicode string, optionally followed by additional binary data.
+
+ @retval EFI_INVALID_PARAMETER ImageHandle is either an invalid image handle or the image
+ has already been initialized with StartImage
+ @retval Exit code from image Exit code from image
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_IMAGE_START)(
+ IN EFI_HANDLE ImageHandle,
+ OUT UINTN *ExitDataSize,
+ OUT CHAR16 **ExitData OPTIONAL
+ );
+
+/**
+ Terminates a loaded EFI image and returns control to boot services.
+
+ @param ImageHandle Handle that identifies the image.
+ @param ExitStatus The image's exit code.
+ @param ExitDataSize The size, in bytes, of ExitData.
+ @param ExitData Pointer to a data buffer that includes a Null-terminated Unicode string,
+ optionally followed by additional binary data.
+
+ @retval EFI_SUCCESS The image specified by ImageHandle was unloaded.
+ @retval EFI_INVALID_PARAMETER The image specified by ImageHandle has been loaded and
+ started with LoadImage() and StartImage(), but the
+ image is not the currently executing image.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_EXIT)(
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_STATUS ExitStatus,
+ IN UINTN ExitDataSize,
+ IN CHAR16 *ExitData OPTIONAL
+ );
+
+/**
+ Unloads an image.
+
+ @param ImageHandle Handle that identifies the image to be unloaded.
+
+ @retval EFI_SUCCESS The image has been unloaded.
+ @retval EFI_INVALID_PARAMETER ImageHandle is not a valid image handle.
+ @retval EFI_UNSUPPORTED The image has been started, and does not support unload.
+ @retval Exit code from the image's unload handler
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_IMAGE_UNLOAD)(
+ IN EFI_HANDLE ImageHandle
+ );
+
+/**
+ Terminates all boot services.
+
+ @param ImageHandle Handle that identifies the exiting image.
+ @param MapKey Key to the latest memory map.
+
+ @retval EFI_SUCCESS Boot services have been terminated.
+ @retval EFI_INVALID_PARAMETER MapKey is incorrect.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_EXIT_BOOT_SERVICES)(
+ IN EFI_HANDLE ImageHandle,
+ IN UINTN MapKey
+ );
+
+/**
+ Induces a fine-grained stall.
+
+ @param Microseconds The number of microseconds to stall execution.
+
+ @retval EFI_SUCCESS Execution was stalled at least the requested number of
+ Microseconds.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_STALL)(
+ IN UINTN Microseconds
+ );
+
+/**
+ Sets the system's watchdog timer.
+
+ @param Timeout The number of seconds to set the watchdog timer to.
+ @param WatchdogCode The numeric code to log on a watchdog timer timeout event.
+ @param DataSize The size, in bytes, of WatchdogData.
+ @param WatchdogData A data buffer that includes a Null-terminated Unicode string, optionally
+ followed by additional binary data.
+
+ @retval EFI_SUCCESS The timeout has been set.
+ @retval EFI_INVALID_PARAMETER The supplied WatchdogCode is invalid.
+ @retval EFI_UNSUPPORTED The system does not have a watchdog timer.
+ @retval EFI_DEVICE_ERROR The watch dog timer could not be programmed due to a hardware
+ error.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SET_WATCHDOG_TIMER)(
+ IN UINTN Timeout,
+ IN UINT64 WatchdogCode,
+ IN UINTN DataSize,
+ IN CHAR16 *WatchdogData OPTIONAL
+ );
+
+//
+// Enumeration of reset types.
+//
+typedef enum {
+ EfiResetCold,
+ EfiResetWarm,
+ EfiResetShutdown,
+ EfiResetUpdate
+} EFI_RESET_TYPE;
+
+/**
+ Resets the entire platform.
+
+ @param ResetType The type of reset to perform.
+ @param ResetStatus The status code for the reset.
+ @param DataSize The size, in bytes, of WatchdogData.
+ @param ResetData For a ResetType of EfiResetCold, EfiResetWarm, or
+ EfiResetShutdown the data buffer starts with a Null-terminated
+ Unicode string, optionally followed by additional binary data.
+
+**/
+typedef
+VOID
+(EFIAPI *EFI_RESET_SYSTEM)(
+ IN EFI_RESET_TYPE ResetType,
+ IN EFI_STATUS ResetStatus,
+ IN UINTN DataSize,
+ IN CHAR16 *ResetData OPTIONAL
+ );
+
+/**
+ Returns a monotonically increasing count for the platform.
+
+ @param Count Pointer to returned value.
+
+ @retval EFI_SUCCESS The next monotonic count was returned.
+ @retval EFI_INVALID_PARAMETER Count is NULL.
+ @retval EFI_DEVICE_ERROR The device is not functioning properly.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_GET_NEXT_MONOTONIC_COUNT)(
+ OUT UINT64 *Count
+ );
+
+/**
+ Returns the next high 32 bits of the platform's monotonic counter.
+
+ @param HighCount Pointer to returned value.
+
+ @retval EFI_SUCCESS The next high monotonic count was returned.
+ @retval EFI_INVALID_PARAMETER HighCount is NULL.
+ @retval EFI_DEVICE_ERROR The device is not functioning properly.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_GET_NEXT_HIGH_MONO_COUNT)(
+ OUT UINT32 *HighCount
+ );
+
+/**
+ Computes and returns a 32-bit CRC for a data buffer.
+
+ @param Data A pointer to the buffer on which the 32-bit CRC is to be computed.
+ @param DataSize The number of bytes in the buffer Data.
+ @param Crc32 The 32-bit CRC that was computed for the data buffer specified by Data
+ and DataSize.
+
+ @retval EFI_SUCCESS The 32-bit CRC was computed for the data buffer and returned in
+ Crc32.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_CALCULATE_CRC32)(
+ IN VOID *Data,
+ IN UINTN DataSize,
+ OUT UINT32 *Crc32
+ );
+
+/**
+ Copies the contents of one buffer to another buffer.
+
+ @param Destination Pointer to the destination buffer of the memory copy.
+ @param Source Pointer to the source buffer of the memory copy.
+ @param Length Number of bytes to copy from Source to Destination.
+
+**/
+typedef
+VOID
+(EFIAPI *EFI_COPY_MEM)(
+ IN VOID *Destination,
+ IN VOID *Source,
+ IN UINTN Length
+ );
+
+/**
+ The SetMem() function fills a buffer with a specified value.
+
+ @param Buffer Pointer to the buffer to fill.
+ @param Size Number of bytes in Buffer to fill.
+ @param Value Value to fill Buffer with.
+
+**/
+typedef
+VOID
+(EFIAPI *EFI_SET_MEM)(
+ IN VOID *Buffer,
+ IN UINTN Size,
+ IN UINT8 Value
+ );
+
+
+//
+// Protocol handler functions
+//
+typedef enum {
+ EFI_NATIVE_INTERFACE
+} EFI_INTERFACE_TYPE;
+
+/**
+ Installs a protocol interface on a device handle. If the handle does not exist, it is created and added
+ to the list of handles in the system. InstallMultipleProtocolInterfaces() performs
+ more error checking than InstallProtocolInterface(), so it is recommended that
+ InstallMultipleProtocolInterfaces() be used in place of
+ InstallProtocolInterface()
+
+ @param Handle A pointer to the EFI_HANDLE on which the interface is to be installed.
+ @param Protocol The numeric ID of the protocol interface.
+ @param InterfaceType Indicates whether Interface is supplied in native form.
+ @param Interface A pointer to the protocol interface.
+
+ @retval EFI_SUCCESS The protocol interface was installed.
+ @retval EFI_OUT_OF_RESOURCES Space for a new handle could not be allocated.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_INSTALL_PROTOCOL_INTERFACE)(
+ IN OUT EFI_HANDLE *Handle,
+ IN EFI_GUID *Protocol,
+ IN EFI_INTERFACE_TYPE InterfaceType,
+ IN VOID *Interface
+ );
+
+/**
+ Installs one or more protocol interfaces into the boot services environment.
+
+ @param Handle The handle to install the new protocol interfaces on, or NULL if a new
+ handle is to be allocated.
+ @param ... A variable argument list containing pairs of protocol GUIDs and protocol
+ interfaces.
+
+ @retval EFI_SUCCESS All the protocol interface was installed.
+ @retval EFI_OUT_OF_RESOURCES There was not enough memory in pool to install all the protocols.
+ @retval EFI_ALREADY_STARTED A Device Path Protocol instance was passed in that is already present in
+ the handle database.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_INSTALL_MULTIPLE_PROTOCOL_INTERFACES)(
+ IN OUT EFI_HANDLE *Handle,
+ ...
+ );
+
+/**
+ Reinstalls a protocol interface on a device handle.
+
+ @param Handle Handle on which the interface is to be reinstalled.
+ @param Protocol The numeric ID of the interface.
+ @param OldInterface A pointer to the old interface. NULL can be used if a structure is not
+ associated with Protocol.
+ @param NewInterface A pointer to the new interface.
+
+ @retval EFI_SUCCESS The protocol interface was reinstalled.
+ @retval EFI_NOT_FOUND The OldInterface on the handle was not found.
+ @retval EFI_ACCESS_DENIED The protocol interface could not be reinstalled,
+ because OldInterface is still being used by a
+ driver that will not release it.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_REINSTALL_PROTOCOL_INTERFACE)(
+ IN EFI_HANDLE Handle,
+ IN EFI_GUID *Protocol,
+ IN VOID *OldInterface,
+ IN VOID *NewInterface
+ );
+
+/**
+ Removes a protocol interface from a device handle. It is recommended that
+ UninstallMultipleProtocolInterfaces() be used in place of
+ UninstallProtocolInterface().
+
+ @param Handle The handle on which the interface was installed.
+ @param Protocol The numeric ID of the interface.
+ @param Interface A pointer to the interface.
+
+ @retval EFI_SUCCESS The interface was removed.
+ @retval EFI_NOT_FOUND The interface was not found.
+ @retval EFI_ACCESS_DENIED The interface was not removed because the interface
+ is still being used by a driver.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_UNINSTALL_PROTOCOL_INTERFACE)(
+ IN EFI_HANDLE Handle,
+ IN EFI_GUID *Protocol,
+ IN VOID *Interface
+ );
+
+/**
+ Removes one or more protocol interfaces into the boot services environment.
+
+ @param Handle The handle to remove the protocol interfaces from.
+ @param ... A variable argument list containing pairs of protocol GUIDs and
+ protocol interfaces.
+
+ @retval EFI_SUCCESS All the protocol interfaces were removed.
+ @retval EFI_INVALID_PARAMETER One of the protocol interfaces was not previously installed on Handle.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_UNINSTALL_MULTIPLE_PROTOCOL_INTERFACES)(
+ IN EFI_HANDLE Handle,
+ ...
+ );
+
+/**
+ Queries a handle to determine if it supports a specified protocol.
+
+ @param Handle The handle being queried.
+ @param Protocol The published unique identifier of the protocol.
+ @param Interface Supplies the address where a pointer to the corresponding Protocol
+ Interface is returned.
+ @retval EFI_SUCCESS The interface information for the specified protocol was returned.
+ @retval EFI_UNSUPPORTED The device does not support the specified protocol.
+ @retval EFI_INVALID_PARAMETER One of the protocol interfaces was not previously installed on Handle.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_HANDLE_PROTOCOL)(
+ IN EFI_HANDLE Handle,
+ IN EFI_GUID *Protocol,
+ OUT VOID **Interface
+ );
+
+#define EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL 0x00000001
+#define EFI_OPEN_PROTOCOL_GET_PROTOCOL 0x00000002
+#define EFI_OPEN_PROTOCOL_TEST_PROTOCOL 0x00000004
+#define EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER 0x00000008
+#define EFI_OPEN_PROTOCOL_BY_DRIVER 0x00000010
+#define EFI_OPEN_PROTOCOL_EXCLUSIVE 0x00000020
+
+/**
+ Queries a handle to determine if it supports a specified protocol. If the protocol is supported by the
+ handle, it opens the protocol on behalf of the calling agent.
+
+ @param Handle The handle for the protocol interface that is being opened.
+ @param Protocol The published unique identifier of the protocol.
+ @param Interface Supplies the address where a pointer to the corresponding Protocol
+ Interface is returned.
+ @param AgentHandle The handle of the agent that is opening the protocol interface
+ specified by Protocol and Interface.
+ @param ControllerHandle If the agent that is opening a protocol is a driver that follows the
+ UEFI Driver Model, then this parameter is the controller handle
+ that requires the protocol interface. If the agent does not follow
+ the UEFI Driver Model, then this parameter is optional and may
+ be NULL.
+ @param Attributes The open mode of the protocol interface specified by Handle
+ and Protocol.
+
+ @retval EFI_SUCCESS An item was added to the open list for the protocol interface, and the
+ protocol interface was returned in Interface.
+ @retval EFI_UNSUPPORTED Handle does not support Protocol.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_ACCESS_DENIED Required attributes can't be supported in current environment.
+ @retval EFI_ALREADY_STARTED Item on the open list already has requierd attributes whose agent
+ handle is the same as AgentHandle.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_OPEN_PROTOCOL)(
+ IN EFI_HANDLE Handle,
+ IN EFI_GUID *Protocol,
+ OUT VOID **Interface,
+ IN EFI_HANDLE AgentHandle,
+ IN EFI_HANDLE ControllerHandle, OPTIONAL
+ IN UINT32 Attributes
+ );
+
+
+/**
+ Closes a protocol on a handle that was opened using OpenProtocol().
+
+ @param Handle The handle for the protocol interface that was previously opened
+ with OpenProtocol(), and is now being closed.
+ @param Protocol The published unique identifier of the protocol.
+ @param Interface Supplies the address where a pointer to the corresponding Protocol
+ Interface is returned.
+ @param AgentHandle The handle of the agent that is closing the protocol interface.
+ @param ControllerHandle If the agent that opened a protocol is a driver that follows the
+ UEFI Driver Model, then this parameter is the controller handle
+ that required the protocol interface.
+
+ @retval EFI_SUCCESS The protocol instance was closed.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_NOT_FOUND 1) Handle does not support the protocol specified by Protocol.
+ 2) The protocol interface specified by Handle and Protocol is not
+ currently open by AgentHandle and ControllerHandle.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_CLOSE_PROTOCOL)(
+ IN EFI_HANDLE Handle,
+ IN EFI_GUID *Protocol,
+ IN EFI_HANDLE AgentHandle,
+ IN EFI_HANDLE ControllerHandle
+ );
+
+
+typedef struct {
+ EFI_HANDLE AgentHandle;
+ EFI_HANDLE ControllerHandle;
+ UINT32 Attributes;
+ UINT32 OpenCount;
+} EFI_OPEN_PROTOCOL_INFORMATION_ENTRY;
+
+/**
+ Retrieves the list of agents that currently have a protocol interface opened.
+
+ @param Handle The handle for the protocol interface that is being queried.
+ @param Protocol The published unique identifier of the protocol.
+ @param EntryBuffer A pointer to a buffer of open protocol information in the form of
+ EFI_OPEN_PROTOCOL_INFORMATION_ENTRY structures.
+ @param EntryCount A pointer to the number of entries in EntryBuffer.
+
+ @retval EFI_SUCCESS The open protocol information was returned in EntryBuffer, and the
+ number of entries was returned EntryCount.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources available to allocate EntryBuffer.
+ @retval EFI_NOT_FOUND Handle does not support the protocol specified by Protocol.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_OPEN_PROTOCOL_INFORMATION)(
+ IN EFI_HANDLE Handle,
+ IN EFI_GUID *Protocol,
+ IN EFI_OPEN_PROTOCOL_INFORMATION_ENTRY **EntryBuffer,
+ OUT UINTN *EntryCount
+ );
+
+/**
+ Retrieves the list of protocol interface GUIDs that are installed on a handle in a buffer allocated
+ from pool.
+
+ @param Handle The handle from which to retrieve the list of protocol interface
+ GUIDs.
+ @param ProtocolBuffer A pointer to the list of protocol interface GUID pointers that are
+ installed on Handle.
+ @param ProtocolBufferCount A pointer to the number of GUID pointers present in
+ ProtocolBuffer.
+
+ @retval EFI_SUCCESS The list of protocol interface GUIDs installed on Handle was returned in
+ ProtocolBuffer. The number of protocol interface GUIDs was
+ returned in ProtocolBufferCount.
+ @retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store the results.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PROTOCOLS_PER_HANDLE)(
+ IN EFI_HANDLE Handle,
+ OUT EFI_GUID ***ProtocolBuffer,
+ OUT UINTN *ProtocolBufferCount
+ );
+
+/**
+ Creates an event that is to be signaled whenever an interface is installed for a specified protocol.
+
+ @param Protocol The numeric ID of the protocol for which the event is to be registered.
+ @param Event Event that is to be signaled whenever a protocol interface is registered
+ for Protocol.
+ @param Registration A pointer to a memory location to receive the registration value.
+
+ @retval EFI_SUCCESS The notification event has been registered.
+ @retval EFI_OUT_OF_RESOURCES Space for the notification event could not be allocated.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_REGISTER_PROTOCOL_NOTIFY)(
+ IN EFI_GUID *Protocol,
+ IN EFI_EVENT Event,
+ OUT VOID **Registration
+ );
+
+
+typedef enum {
+ AllHandles,
+ ByRegisterNotify,
+ ByProtocol
+} EFI_LOCATE_SEARCH_TYPE;
+
+/**
+ Returns an array of handles that support a specified protocol.
+
+ @param SearchType Specifies which handle(s) are to be returned.
+ @param Protocol Specifies the protocol to search by.
+ @param SearchKey Specifies the search key.
+ @param BufferSize On input, the size in bytes of Buffer. On output, the size in bytes of
+ the array returned in Buffer (if the buffer was large enough) or the
+ size, in bytes, of the buffer needed to obtain the array (if the buffer was
+ not large enough).
+ @param Buffer The buffer in which the array is returned.
+
+ @retval EFI_SUCCESS The array of handles was returned.
+ @retval EFI_NOT_FOUND No handles match the search.
+ @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small for the result.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_LOCATE_HANDLE)(
+ IN EFI_LOCATE_SEARCH_TYPE SearchType,
+ IN EFI_GUID *Protocol, OPTIONAL
+ IN VOID *SearchKey, OPTIONAL
+ IN OUT UINTN *BufferSize,
+ OUT EFI_HANDLE *Buffer
+ );
+
+/**
+ Locates the handle to a device on the device path that supports the specified protocol.
+
+ @param Protocol Specifies the protocol to search for.
+ @param DevicePath On input, a pointer to a pointer to the device path. On output, the device
+ path pointer is modified to point to the remaining part of the device
+ path.
+ @param Device A pointer to the returned device handle.
+
+ @retval EFI_SUCCESS The resulting handle was returned.
+ @retval EFI_NOT_FOUND No handles match the search.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_LOCATE_DEVICE_PATH)(
+ IN EFI_GUID *Protocol,
+ IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath,
+ OUT EFI_HANDLE *Device
+ );
+
+/**
+ Adds, updates, or removes a configuration table entry from the EFI System Table.
+
+ @param Guid A pointer to the GUID for the entry to add, update, or remove.
+ @param Table A pointer to the configuration table for the entry to add, update, or
+ remove. May be NULL.
+
+ @retval EFI_SUCCESS The (Guid, Table) pair was added, updated, or removed.
+ @retval EFI_NOT_FOUND An attempt was made to delete a nonexistent entry.
+ @retval EFI_INVALID_PARAMETER Guid is not valid.
+ @retval EFI_OUT_OF_RESOURCES There is not enough memory available to complete the operation.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_INSTALL_CONFIGURATION_TABLE)(
+ IN EFI_GUID *Guid,
+ IN VOID *Table
+ );
+
+
+/**
+ Returns an array of handles that support the requested protocol in a buffer allocated from pool.
+
+ @param SearchType Specifies which handle(s) are to be returned.
+ @param Protocol Specifies the protocol to search by.
+ @param SearchKey Supplies the search key depending on the SearchType.
+ @param NoHandles The number of handles returned in Buffer.
+ @param Buffer A pointer to the buffer to return the requested array of handles that
+ support Protocol.
+
+ @retval EFI_SUCCESS The array of handles was returned in Buffer, and the number of
+ handles in Buffer was returned in NoHandles.
+ @retval EFI_NOT_FOUND No handles match the search.
+ @retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store the matching results.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_LOCATE_HANDLE_BUFFER)(
+ IN EFI_LOCATE_SEARCH_TYPE SearchType,
+ IN EFI_GUID *Protocol, OPTIONAL
+ IN VOID *SearchKey, OPTIONAL
+ IN OUT UINTN *NoHandles,
+ OUT EFI_HANDLE **Buffer
+ );
+
+/**
+ Returns the first protocol instance that matches the given protocol.
+
+ @param Protocol Provides the protocol to search for.
+ @param Registration Optional registration key returned from
+ RegisterProtocolNotify().
+ @param Interface On return, a pointer to the first interface that matches Protocol and
+ Registration.
+
+ @retval EFI_SUCCESS A protocol instance matching Protocol was found and returned in
+ Interface.
+ @retval EFI_NOT_FOUND No protocol instances were found that match Protocol and
+ Registration.
+ @retval EFI_INVALID_PARAMETER Interface is NULL.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_LOCATE_PROTOCOL)(
+ IN EFI_GUID *Protocol,
+ IN VOID *Registration, OPTIONAL
+ OUT VOID **Interface
+ );
+
+typedef struct {
+ UINT64 Length;
+ union {
+ EFI_PHYSICAL_ADDRESS DataBlock;
+ EFI_PHYSICAL_ADDRESS ContinuationPointer;
+ } Union;
+} EFI_CAPSULE_BLOCK_DESCRIPTOR;
+
+typedef struct {
+ EFI_GUID CapsuleGuid;
+ UINT32 HeaderSize;
+ UINT32 Flags;
+ UINT32 CapsuleImageSize;
+} EFI_CAPSULE_HEADER;
+
+typedef struct {
+ UINT32 CapsuleArrayNumber;
+ VOID* CapsulePtr[1];
+} EFI_CAPSULE_TABLE;
+
+#define CAPSULE_FLAGS_PERSIST_ACROSS_RESET 0x00010000
+#define CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE 0x00020000
+
+/**
+ Passes capsules to the firmware with both virtual and physical mapping. Depending on the intended
+ consumption, the firmware may process the capsule immediately. If the payload should persist
+ across a system reset, the reset value returned from EFI_QueryCapsuleCapabilities must
+ be passed into ResetSystem() and will cause the capsule to be processed by the firmware as
+ part of the reset process.
+
+ @param CapsuleHeaderArray Virtual pointer to an array of virtual pointers to the capsules
+ being passed into update capsule.
+ @param CapsuleCount Number of pointers to EFI_CAPSULE_HEADER in
+ CaspuleHeaderArray.
+ @param ScatterGatherList Physical pointer to a set of
+ EFI_CAPSULE_BLOCK_DESCRIPTOR that describes the
+ location in physical memory of a set of capsules.
+
+ @retval EFI_SUCCESS Valid capsule was passed. If
+ CAPSULE_FLAGS_PERSIT_ACROSS_RESET is not set, the
+ capsule has been successfully processed by the firmware.
+ @retval EFI_DEVICE_ERROR The capsule update was started, but failed due to a device error.
+ @retval EFI_INVALID_PARAMETER CapsuleSize is NULL.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_UPDATE_CAPSULE)(
+ IN EFI_CAPSULE_HEADER **CapsuleHeaderArray,
+ IN UINTN CapsuleCount,
+ IN EFI_PHYSICAL_ADDRESS ScatterGatherList OPTIONAL
+ );
+
+/**
+ Returns if the capsule can be supported via UpdateCapsule().
+
+ @param CapsuleHeaderArray Virtual pointer to an array of virtual pointers to the capsules
+ being passed into update capsule.
+ @param CapsuleCount Number of pointers to EFI_CAPSULE_HEADER in
+ CaspuleHeaderArray.
+ @param MaxiumCapsuleSize On output the maximum size that UpdateCapsule() can
+ support as an argument to UpdateCapsule() via
+ CapsuleHeaderArray and ScatterGatherList.
+ @param ResetType Returns the type of reset required for the capsule update.
+
+ @retval EFI_SUCCESS Valid answer returned.
+ @retval EFI_UNSUPPORTED The capsule type is not supported on this platform, and
+ MaximumCapsuleSize and ResetType are undefined.
+ @retval EFI_INVALID_PARAMETER MaximumCapsuleSize is NULL.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_QUERY_CAPSULE_CAPABILITIES)(
+ IN EFI_CAPSULE_HEADER **CapsuleHeaderArray,
+ IN UINTN CapsuleCount,
+ OUT UINT64 *MaximumCapsuleSize,
+ OUT EFI_RESET_TYPE *ResetType
+ );
+
+/**
+ Returns information about the EFI variables.
+
+ @param Attributes Attributes bitmask to specify the type of variables on
+ which to return information.
+ @param MaximumVariableStorageSize On output the maximum size of the storage space
+ available for the EFI variables associated with the
+ attributes specified.
+ @param RemainingVariableStorageSize Returns the remaining size of the storage space
+ available for the EFI variables associated with the
+ attributes specified.
+ @param MaximumVariableSize Returns the maximum size of the individual EFI
+ variables associated with the attributes specified.
+
+ @retval EFI_SUCCESS Valid answer returned.
+ @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied
+ @retval EFI_UNSUPPORTED The attribute is not supported on this platform, and the
+ MaximumVariableStorageSize,
+ RemainingVariableStorageSize, MaximumVariableSize
+ are undefined.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_QUERY_VARIABLE_INFO)(
+ IN UINT32 Attributes,
+ OUT UINT64 *MaximumVariableStorageSize,
+ OUT UINT64 *RemainingVariableStorageSize,
+ OUT UINT64 *MaximumVariableSize
+ );
+
+
+//
+// EFI Runtime Services Table
+//
+#define EFI_SYSTEM_TABLE_SIGNATURE 0x5453595320494249ULL
+#define EFI_SYSTEM_TABLE_REVISION ((2<<16) | (10))
+#define EFI_2_10_SYSTEM_TABLE_REVISION ((2<<16) | (10))
+#define EFI_2_00_SYSTEM_TABLE_REVISION ((2<<16) | (00))
+#define EFI_1_10_SYSTEM_TABLE_REVISION ((1<<16) | (10))
+#define EFI_1_02_SYSTEM_TABLE_REVISION ((1<<16) | (02))
+
+#define EFI_RUNTIME_SERVICES_SIGNATURE 0x56524553544e5552ULL
+#define EFI_RUNTIME_SERVICES_REVISION EFI_2_10_SYSTEM_TABLE_REVISION
+
+typedef struct {
+ EFI_TABLE_HEADER Hdr;
+
+ //
+ // Time Services
+ //
+ EFI_GET_TIME GetTime;
+ EFI_SET_TIME SetTime;
+ EFI_GET_WAKEUP_TIME GetWakeupTime;
+ EFI_SET_WAKEUP_TIME SetWakeupTime;
+
+ //
+ // Virtual Memory Services
+ //
+ EFI_SET_VIRTUAL_ADDRESS_MAP SetVirtualAddressMap;
+ EFI_CONVERT_POINTER ConvertPointer;
+
+ //
+ // Variable Services
+ //
+ EFI_GET_VARIABLE GetVariable;
+ EFI_GET_NEXT_VARIABLE_NAME GetNextVariableName;
+ EFI_SET_VARIABLE SetVariable;
+
+ //
+ // Miscellaneous Services
+ //
+ EFI_GET_NEXT_HIGH_MONO_COUNT GetNextHighMonotonicCount;
+ EFI_RESET_SYSTEM ResetSystem;
+
+ //
+ // UEFI 2.0 Capsule Services
+ //
+ EFI_UPDATE_CAPSULE UpdateCapsule;
+ EFI_QUERY_CAPSULE_CAPABILITIES QueryCapsuleCapabilities;
+
+ //
+ // Miscellaneous UEFI 2.0 Service
+ //
+ EFI_QUERY_VARIABLE_INFO QueryVariableInfo;
+} EFI_RUNTIME_SERVICES;
+
+
+#define EFI_BOOT_SERVICES_SIGNATURE 0x56524553544f4f42ULL
+#define EFI_BOOT_SERVICES_REVISION EFI_2_10_SYSTEM_TABLE_REVISION
+
+typedef struct {
+ EFI_TABLE_HEADER Hdr;
+
+ //
+ // Task Priority Services
+ //
+ EFI_RAISE_TPL RaiseTPL;
+ EFI_RESTORE_TPL RestoreTPL;
+
+ //
+ // Memory Services
+ //
+ EFI_ALLOCATE_PAGES AllocatePages;
+ EFI_FREE_PAGES FreePages;
+ EFI_GET_MEMORY_MAP GetMemoryMap;
+ EFI_ALLOCATE_POOL AllocatePool;
+ EFI_FREE_POOL FreePool;
+
+ //
+ // Event & Timer Services
+ //
+ EFI_CREATE_EVENT CreateEvent;
+ EFI_SET_TIMER SetTimer;
+ EFI_WAIT_FOR_EVENT WaitForEvent;
+ EFI_SIGNAL_EVENT SignalEvent;
+ EFI_CLOSE_EVENT CloseEvent;
+ EFI_CHECK_EVENT CheckEvent;
+
+ //
+ // Protocol Handler Services
+ //
+ EFI_INSTALL_PROTOCOL_INTERFACE InstallProtocolInterface;
+ EFI_REINSTALL_PROTOCOL_INTERFACE ReinstallProtocolInterface;
+ EFI_UNINSTALL_PROTOCOL_INTERFACE UninstallProtocolInterface;
+ EFI_HANDLE_PROTOCOL HandleProtocol;
+ VOID *Reserved;
+ EFI_REGISTER_PROTOCOL_NOTIFY RegisterProtocolNotify;
+ EFI_LOCATE_HANDLE LocateHandle;
+ EFI_LOCATE_DEVICE_PATH LocateDevicePath;
+ EFI_INSTALL_CONFIGURATION_TABLE InstallConfigurationTable;
+
+ //
+ // Image Services
+ //
+ EFI_IMAGE_LOAD LoadImage;
+ EFI_IMAGE_START StartImage;
+ EFI_EXIT Exit;
+ EFI_IMAGE_UNLOAD UnloadImage;
+ EFI_EXIT_BOOT_SERVICES ExitBootServices;
+
+ //
+ // Miscellaneous Services
+ //
+ EFI_GET_NEXT_MONOTONIC_COUNT GetNextMonotonicCount;
+ EFI_STALL Stall;
+ EFI_SET_WATCHDOG_TIMER SetWatchdogTimer;
+
+ //
+ // DriverSupport Services
+ //
+ EFI_CONNECT_CONTROLLER ConnectController;
+ EFI_DISCONNECT_CONTROLLER DisconnectController;
+
+ //
+ // Open and Close Protocol Services
+ //
+ EFI_OPEN_PROTOCOL OpenProtocol;
+ EFI_CLOSE_PROTOCOL CloseProtocol;
+ EFI_OPEN_PROTOCOL_INFORMATION OpenProtocolInformation;
+
+ //
+ // Library Services
+ //
+ EFI_PROTOCOLS_PER_HANDLE ProtocolsPerHandle;
+ EFI_LOCATE_HANDLE_BUFFER LocateHandleBuffer;
+ EFI_LOCATE_PROTOCOL LocateProtocol;
+ EFI_INSTALL_MULTIPLE_PROTOCOL_INTERFACES InstallMultipleProtocolInterfaces;
+ EFI_UNINSTALL_MULTIPLE_PROTOCOL_INTERFACES UninstallMultipleProtocolInterfaces;
+
+ //
+ // 32-bit CRC Services
+ //
+ EFI_CALCULATE_CRC32 CalculateCrc32;
+
+ //
+ // Miscellaneous Services
+ //
+ EFI_COPY_MEM CopyMem;
+ EFI_SET_MEM SetMem;
+
+ EFI_CREATE_EVENT_EX CreateEventEx;
+} EFI_BOOT_SERVICES;
+
+//
+// Contains a set of GUID/pointer pairs comprised of the ConfigurationTable field in the
+// EFI System Table.
+//
+typedef struct{
+ EFI_GUID VendorGuid;
+ VOID *VendorTable;
+} EFI_CONFIGURATION_TABLE;
+
+struct _EFI_SYSTEM_TABLE {
+ EFI_TABLE_HEADER Hdr;
+ CHAR16 *FirmwareVendor;
+ UINT32 FirmwareRevision;
+ EFI_HANDLE ConsoleInHandle;
+ EFI_SIMPLE_TEXT_INPUT_PROTOCOL *ConIn;
+ EFI_HANDLE ConsoleOutHandle;
+ EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut;
+ EFI_HANDLE StandardErrorHandle;
+ EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *StdErr;
+ EFI_RUNTIME_SERVICES *RuntimeServices;
+ EFI_BOOT_SERVICES *BootServices;
+ UINTN NumberOfTableEntries;
+ EFI_CONFIGURATION_TABLE *ConfigurationTable;
+};
+
+//
+// EFI Load Options Attributes
+//
+#define LOAD_OPTION_ACTIVE 0x00000001
+#define LOAD_OPTION_FORCE_RECONNECT 0x00000002
+#define LOAD_OPTION_HIDDEN 0x00000008
+#define LOAD_OPTION_CATEGORY 0x00001F00
+
+#define LOAD_OPTION_CATEGORY_BOOT 0x00000000
+#define LOAD_OPTION_CATEGORY_APP 0x00000100
+
+#define EFI_BOOT_OPTION_SUPPORT_KEY 0x00000001
+#define EFI_BOOT_OPTION_SUPPORT_APP 0x00000002
+#define EFI_BOOT_OPTION_SUPPORT_COUNT 0x00000300
+
+typedef union {
+ struct {
+ UINT32 Revision : 8;
+ UINT32 ShiftPressed : 1;
+ UINT32 ControlPressed : 1;
+ UINT32 AltPressed : 1;
+ UINT32 LogoPressed : 1;
+ UINT32 MenuPressed : 1;
+ UINT32 SysReqPessed : 1;
+ UINT32 Reserved : 16;
+ UINT32 InputKeyCount : 2;
+ } Options;
+ UINT32 PackedValue;
+} HOT_KEY_EFI_KEY_DATA;
+
+typedef struct {
+ HOT_KEY_EFI_KEY_DATA KeyOptions;
+ UINT32 BootOptionCrc;
+ UINT16 BootOption;
+//EFI_INPUT_KEY Keys[];
+} EFI_KEY_OPTION;
+
+#define EFI_KEY_OPTION_SHIFT 0x00000001
+#define EFI_KEY_OPTION_CONTROL 0x00000002
+#define EFI_KEY_OPTION_ALT 0x00000004
+#define EFI_KEY_OPTION_LOGO 0x00000008
+#define EFI_KEY_OPTION_MENU 0x00000010
+#define EFI_KEY_OPTION_SYSREQ 0x00000020
+#define EFI_KEY_CODE_COUNT 0x00000300
+
+
+//
+// EFI File location to boot from on removable media devices
+//
+#define EFI_REMOVABLE_MEDIA_FILE_NAME_IA32 L"\\EFI\\BOOT\\BOOTIA32.EFI"
+#define EFI_REMOVABLE_MEDIA_FILE_NAME_IA64 L"\\EFI\\BOOT\\BOOTIA64.EFI"
+#define EFI_REMOVABLE_MEDIA_FILE_NAME_X64 L"\\EFI\\BOOT\\BOOTX64.EFI"
+#define EFI_REMOVABLE_MEDIA_FILE_NAME_EBC L"\\EFI\\BOOT\\BOOTEBC.EFI"
+
+#if defined (MDE_CPU_IA32)
+ #define EFI_REMOVABLE_MEDIA_FILE_NAME EFI_REMOVABLE_MEDIA_FILE_NAME_IA32
+#elif defined (MDE_CPU_IPF)
+ #define EFI_REMOVABLE_MEDIA_FILE_NAME EFI_REMOVABLE_MEDIA_FILE_NAME_IA64
+#elif defined (MDE_CPU_X64)
+ #define EFI_REMOVABLE_MEDIA_FILE_NAME EFI_REMOVABLE_MEDIA_FILE_NAME_X64
+#elif defined (MDE_CPU_EBC)
+ #define EFI_REMOVABLE_MEDIA_FILE_NAME EFI_REMOVABLE_MEDIA_FILE_NAME_EBC
+#else
+ #error Unknown Processor Type
+#endif
+
+#include <gpxe/efi/Uefi/UefiPxe.h>
+#include <gpxe/efi/Uefi/UefiGpt.h>
+#include <gpxe/efi/Uefi/UefiInternalFormRepresentation.h>
+
+#endif
diff --git a/gpxe/src/include/gpxe/efi/efi.h b/gpxe/src/include/gpxe/efi/efi.h
new file mode 100644
index 00000000..0643066f
--- /dev/null
+++ b/gpxe/src/include/gpxe/efi/efi.h
@@ -0,0 +1,89 @@
+#ifndef _EFI_H
+#define _EFI_H
+
+/** @file
+ *
+ * EFI API
+ *
+ * The intention is to include near-verbatim copies of the EFI headers
+ * required by gPXE. This is achieved using the import.pl script in
+ * this directory. Run the import script to update the local copies
+ * of the headers:
+ *
+ * ./import.pl /path/to/edk2/edk2
+ *
+ * where /path/to/edk2/edk2 is the path to your local checkout of the
+ * EFI Development Kit.
+ *
+ * Note that import.pl will modify any #include lines in each imported
+ * header to reflect its new location within the gPXE tree. It will
+ * also tidy up the file by removing carriage return characters and
+ * trailing whitespace.
+ *
+ *
+ * At the time of writing, there are a few other modifications to
+ * these headers that are present in my personal edk2 tree, that are
+ * not yet committed back to the main edk2 repository. These
+ * modifications are fixes for compilation on case-dependent
+ * filesystems, compilation under -mrtd and -mregparm=3, etc.
+ */
+
+/* Include the top-level EFI header file */
+#include <gpxe/efi/Uefi.h>
+
+/* Reset any trailing #pragma pack directives */
+#pragma pack()
+
+#include <gpxe/tables.h>
+#include <gpxe/uuid.h>
+
+/** An EFI protocol used by gPXE */
+struct efi_protocol {
+ union {
+ /** EFI protocol GUID */
+ EFI_GUID guid;
+ /** UUID structure understood by gPXE */
+ union uuid uuid;
+ } u;
+ /** Variable containing pointer to protocol structure */
+ void **protocol;
+};
+
+/** Declare an EFI protocol used by gPXE */
+#define __efi_protocol \
+ __table ( struct efi_protocol, efi_protocols, 01 )
+
+/** Declare an EFI protocol to be required by gPXE
+ *
+ * @v _protocol EFI protocol name
+ * @v _ptr Pointer to protocol instance
+ */
+#define EFI_REQUIRE_PROTOCOL( _protocol, _ptr ) \
+ struct efi_protocol __ ## _protocol __efi_protocol = { \
+ .u.guid = _protocol ## _GUID, \
+ .protocol = ( ( void ** ) ( void * ) \
+ ( ( (_ptr) == ( ( _protocol ** ) NULL ) ) ? \
+ (_ptr) : (_ptr) ) ), \
+ }
+
+/** Convert a gPXE status code to an EFI status code
+ *
+ * FIXME: actually perform some kind of conversion. gPXE error codes
+ * will be detected as EFI error codes; both have the top bit set, and
+ * the success return code is zero for both. Anything that just
+ * reports a numerical error will be OK, anything attempting to
+ * interpret the value or to display a text equivalent will be
+ * screwed.
+ */
+#define RC_TO_EFIRC( rc ) (rc)
+
+/** Convert an EFI status code to a gPXE status code
+ *
+ * FIXME: as above
+ */
+#define EFIRC_TO_RC( efirc ) (efirc)
+
+extern EFI_HANDLE efi_image_handle;
+extern EFI_SYSTEM_TABLE *efi_systab;
+
+#endif /* _EFI_H */
diff --git a/gpxe/src/include/gpxe/efi/efi_io.h b/gpxe/src/include/gpxe/efi/efi_io.h
new file mode 100644
index 00000000..93f559db
--- /dev/null
+++ b/gpxe/src/include/gpxe/efi/efi_io.h
@@ -0,0 +1,178 @@
+#ifndef _GPXE_EFI_IO_H
+#define _GPXE_EFI_IO_H
+
+/** @file
+ *
+ * gPXE I/O API for EFI
+ *
+ * EFI runs with flat physical addressing, so the various mappings
+ * between virtual addresses, I/O addresses and bus addresses are all
+ * no-ops. I/O is handled using the EFI_CPU_IO_PROTOCOL.
+ */
+
+#ifdef IOAPI_EFI
+#define IOAPI_PREFIX_efi
+#else
+#define IOAPI_PREFIX_efi __efi_
+#endif
+
+extern unsigned long long efi_ioread ( volatile void *io_addr,
+ size_t size );
+extern void efi_iowrite ( unsigned long long data, volatile void *io_addr,
+ size_t size );
+extern void efi_ioreads ( volatile void *io_addr, void *data,
+ size_t size, unsigned int count );
+extern void efi_iowrites ( volatile void *io_addr, const void *data,
+ size_t size, unsigned int count );
+
+/*
+ * Physical<->Bus and Bus<->I/O address mappings
+ *
+ * EFI runs with flat physical addressing, so these are all no-ops.
+ *
+ */
+
+static inline __always_inline unsigned long
+IOAPI_INLINE ( efi, phys_to_bus ) ( unsigned long phys_addr ) {
+ return phys_addr;
+}
+
+static inline __always_inline unsigned long
+IOAPI_INLINE ( efi, bus_to_phys ) ( unsigned long bus_addr ) {
+ return bus_addr;
+}
+
+static inline __always_inline void *
+IOAPI_INLINE ( efi, ioremap ) ( unsigned long bus_addr, size_t len __unused ) {
+ return ( ( void * ) bus_addr );
+}
+
+static inline __always_inline void
+IOAPI_INLINE ( efi, iounmap ) ( volatile const void *io_addr __unused ) {
+ /* Nothing to do */
+}
+
+static inline __always_inline unsigned long
+IOAPI_INLINE ( efi, io_to_bus ) ( volatile const void *io_addr ) {
+ return ( ( unsigned long ) io_addr );
+}
+
+/*
+ * I/O functions
+ *
+ */
+
+static inline __always_inline uint8_t
+IOAPI_INLINE ( efi, readb ) ( volatile uint8_t *io_addr ) {
+ return efi_ioread ( io_addr, sizeof ( *io_addr ) );
+}
+
+static inline __always_inline uint16_t
+IOAPI_INLINE ( efi, readw ) ( volatile uint16_t *io_addr ) {
+ return efi_ioread ( io_addr, sizeof ( *io_addr ) );
+}
+
+static inline __always_inline uint32_t
+IOAPI_INLINE ( efi, readl ) ( volatile uint32_t *io_addr ) {
+ return efi_ioread ( io_addr, sizeof ( *io_addr ) );
+}
+
+static inline __always_inline uint64_t
+IOAPI_INLINE ( efi, readq ) ( volatile uint64_t *io_addr ) {
+ return efi_ioread ( io_addr, sizeof ( *io_addr ) );
+}
+
+static inline __always_inline void
+IOAPI_INLINE ( efi, writeb ) ( uint8_t data, volatile uint8_t *io_addr ) {
+ efi_iowrite ( data, io_addr, sizeof ( *io_addr ) );
+}
+
+static inline __always_inline void
+IOAPI_INLINE ( efi, writew ) ( uint16_t data, volatile uint16_t *io_addr ) {
+ efi_iowrite ( data, io_addr, sizeof ( *io_addr ) );
+}
+
+static inline __always_inline void
+IOAPI_INLINE ( efi, writel ) ( uint32_t data, volatile uint32_t *io_addr ) {
+ efi_iowrite ( data, io_addr, sizeof ( *io_addr ) );
+}
+
+static inline __always_inline void
+IOAPI_INLINE ( efi, writeq ) ( uint64_t data, volatile uint64_t *io_addr ) {
+ efi_iowrite ( data, io_addr, sizeof ( *io_addr ) );
+}
+
+static inline __always_inline uint8_t
+IOAPI_INLINE ( efi, inb ) ( volatile uint8_t *io_addr ) {
+ return efi_ioread ( io_addr, sizeof ( *io_addr ) );
+}
+
+static inline __always_inline uint16_t
+IOAPI_INLINE ( efi, inw ) ( volatile uint16_t *io_addr ) {
+ return efi_ioread ( io_addr, sizeof ( *io_addr ) );
+}
+
+static inline __always_inline uint32_t
+IOAPI_INLINE ( efi, inl ) ( volatile uint32_t *io_addr ) {
+ return efi_ioread ( io_addr, sizeof ( *io_addr ) );
+}
+
+static inline __always_inline void
+IOAPI_INLINE ( efi, outb ) ( uint8_t data, volatile uint8_t *io_addr ) {
+ efi_iowrite ( data, io_addr, sizeof ( *io_addr ) );
+}
+
+static inline __always_inline void
+IOAPI_INLINE ( efi, outw ) ( uint16_t data, volatile uint16_t *io_addr ) {
+ efi_iowrite ( data, io_addr, sizeof ( *io_addr ) );
+}
+
+static inline __always_inline void
+IOAPI_INLINE ( efi, outl ) ( uint32_t data, volatile uint32_t *io_addr ) {
+ efi_iowrite ( data, io_addr, sizeof ( *io_addr ) );
+}
+
+static inline __always_inline void
+IOAPI_INLINE ( efi, insb ) ( volatile uint8_t *io_addr, uint8_t *data,
+ unsigned int count ) {
+ efi_ioreads ( io_addr, data, sizeof ( *io_addr ), count );
+}
+
+static inline __always_inline void
+IOAPI_INLINE ( efi, insw ) ( volatile uint16_t *io_addr, uint16_t *data,
+ unsigned int count ) {
+ efi_ioreads ( io_addr, data, sizeof ( *io_addr ), count );
+}
+
+static inline __always_inline void
+IOAPI_INLINE ( efi, insl ) ( volatile uint32_t *io_addr, uint32_t *data,
+ unsigned int count ) {
+ efi_ioreads ( io_addr, data, sizeof ( *io_addr ), count );
+}
+
+static inline __always_inline void
+IOAPI_INLINE ( efi, outsb ) ( volatile uint8_t *io_addr, const uint8_t *data,
+ unsigned int count ) {
+ efi_iowrites ( io_addr, data, sizeof ( *io_addr ), count );
+}
+
+static inline __always_inline void
+IOAPI_INLINE ( efi, outsw ) ( volatile uint16_t *io_addr, const uint16_t *data,
+ unsigned int count ) {
+ efi_iowrites ( io_addr, data, sizeof ( *io_addr ), count );
+}
+
+static inline __always_inline void
+IOAPI_INLINE ( efi, outsl ) ( volatile uint32_t *io_addr, const uint32_t *data,
+ unsigned int count ) {
+ efi_iowrites ( io_addr, data, sizeof ( *io_addr ), count );
+}
+
+static inline __always_inline void
+IOAPI_INLINE ( efi, mb ) ( void ) {
+ /* Do nothing; EFI readl()/writel() calls already act as
+ * memory barriers.
+ */
+}
+
+#endif /* _GPXE_EFI_IO_H */
diff --git a/gpxe/src/include/gpxe/efi/efi_pci.h b/gpxe/src/include/gpxe/efi/efi_pci.h
new file mode 100644
index 00000000..8be331ab
--- /dev/null
+++ b/gpxe/src/include/gpxe/efi/efi_pci.h
@@ -0,0 +1,146 @@
+#ifndef _GPXE_EFI_PCI_H
+#define _GPXE_EFI_PCI_H
+
+/** @file
+ *
+ * gPXE PCI I/O API for EFI
+ *
+ */
+
+#ifdef PCIAPI_EFI
+#define PCIAPI_PREFIX_efi
+#else
+#define PCIAPI_PREFIX_efi __efi_
+#endif
+
+/* EFI PCI width codes defined by EFI spec */
+#define EFIPCI_WIDTH_BYTE 0
+#define EFIPCI_WIDTH_WORD 1
+#define EFIPCI_WIDTH_DWORD 2
+
+#define EFIPCI_LOCATION( _offset, _width ) \
+ ( (_offset) | ( (_width) << 16 ) )
+#define EFIPCI_OFFSET( _location ) ( (_location) & 0xffff )
+#define EFIPCI_WIDTH( _location ) ( (_location) >> 16 )
+
+struct pci_device;
+
+extern int efipci_read ( struct pci_device *pci, unsigned long location,
+ void *value );
+extern int efipci_write ( struct pci_device *pci, unsigned long location,
+ unsigned long value );
+
+/**
+ * Determine maximum PCI bus number within system
+ *
+ * @ret max_bus Maximum bus number
+ */
+static inline __always_inline int
+PCIAPI_INLINE ( efi, pci_max_bus ) ( void ) {
+ /* No way to work this out via EFI */
+ return 0xff;
+}
+
+/**
+ * Read byte from PCI configuration space via EFI
+ *
+ * @v pci PCI device
+ * @v where Location within PCI configuration space
+ * @v value Value read
+ * @ret rc Return status code
+ */
+static inline __always_inline int
+PCIAPI_INLINE ( efi, pci_read_config_byte ) ( struct pci_device *pci,
+ unsigned int where,
+ uint8_t *value ) {
+ return efipci_read ( pci,
+ EFIPCI_LOCATION ( where, EFIPCI_WIDTH_BYTE ),
+ value );
+}
+
+/**
+ * Read word from PCI configuration space via EFI
+ *
+ * @v pci PCI device
+ * @v where Location within PCI configuration space
+ * @v value Value read
+ * @ret rc Return status code
+ */
+static inline __always_inline int
+PCIAPI_INLINE ( efi, pci_read_config_word ) ( struct pci_device *pci,
+ unsigned int where,
+ uint16_t *value ) {
+ return efipci_read ( pci,
+ EFIPCI_LOCATION ( where, EFIPCI_WIDTH_WORD ),
+ value );
+}
+
+/**
+ * Read dword from PCI configuration space via EFI
+ *
+ * @v pci PCI device
+ * @v where Location within PCI configuration space
+ * @v value Value read
+ * @ret rc Return status code
+ */
+static inline __always_inline int
+PCIAPI_INLINE ( efi, pci_read_config_dword ) ( struct pci_device *pci,
+ unsigned int where,
+ uint32_t *value ) {
+ return efipci_read ( pci,
+ EFIPCI_LOCATION ( where, EFIPCI_WIDTH_DWORD ),
+ value );
+}
+
+/**
+ * Write byte to PCI configuration space via EFI
+ *
+ * @v pci PCI device
+ * @v where Location within PCI configuration space
+ * @v value Value to be written
+ * @ret rc Return status code
+ */
+static inline __always_inline int
+PCIAPI_INLINE ( efi, pci_write_config_byte ) ( struct pci_device *pci,
+ unsigned int where,
+ uint8_t value ) {
+ return efipci_write ( pci,
+ EFIPCI_LOCATION ( where, EFIPCI_WIDTH_BYTE ),
+ value );
+}
+
+/**
+ * Write word to PCI configuration space via EFI
+ *
+ * @v pci PCI device
+ * @v where Location within PCI configuration space
+ * @v value Value to be written
+ * @ret rc Return status code
+ */
+static inline __always_inline int
+PCIAPI_INLINE ( efi, pci_write_config_word ) ( struct pci_device *pci,
+ unsigned int where,
+ uint16_t value ) {
+ return efipci_write ( pci,
+ EFIPCI_LOCATION ( where, EFIPCI_WIDTH_WORD ),
+ value );
+}
+
+/**
+ * Write dword to PCI configuration space via EFI
+ *
+ * @v pci PCI device
+ * @v where Location within PCI configuration space
+ * @v value Value to be written
+ * @ret rc Return status code
+ */
+static inline __always_inline int
+PCIAPI_INLINE ( efi, pci_write_config_dword ) ( struct pci_device *pci,
+ unsigned int where,
+ uint32_t value ) {
+ return efipci_write ( pci,
+ EFIPCI_LOCATION ( where, EFIPCI_WIDTH_DWORD ),
+ value );
+}
+
+#endif /* _GPXE_EFI_PCI_H */
diff --git a/gpxe/src/include/gpxe/efi/efi_timer.h b/gpxe/src/include/gpxe/efi/efi_timer.h
new file mode 100644
index 00000000..c332c9d6
--- /dev/null
+++ b/gpxe/src/include/gpxe/efi/efi_timer.h
@@ -0,0 +1,16 @@
+#ifndef _GPXE_EFI_TIMER_H
+#define _GPXE_EFI_TIMER_H
+
+/** @file
+ *
+ * gPXE timer API for EFI
+ *
+ */
+
+#ifdef TIMER_EFI
+#define TIMER_PREFIX_efi
+#else
+#define TIMER_PREFIX_efi __efi_
+#endif
+
+#endif /* _GPXE_EFI_TIMER_H */
diff --git a/gpxe/src/include/gpxe/efi/efi_uaccess.h b/gpxe/src/include/gpxe/efi/efi_uaccess.h
new file mode 100644
index 00000000..bae5fb41
--- /dev/null
+++ b/gpxe/src/include/gpxe/efi/efi_uaccess.h
@@ -0,0 +1,88 @@
+#ifndef _GPXE_EFI_UACCESS_H
+#define _GPXE_EFI_UACCESS_H
+
+/** @file
+ *
+ * gPXE user access API for EFI
+ *
+ * EFI runs with flat physical addressing, so the various mappings
+ * between virtual addresses, I/O addresses and bus addresses are all
+ * no-ops.
+ */
+
+#ifdef UACCESS_EFI
+#define UACCESS_PREFIX_efi
+#else
+#define UACCESS_PREFIX_efi __efi_
+#endif
+
+/**
+ * Convert physical address to user pointer
+ *
+ * @v phys_addr Physical address
+ * @ret userptr User pointer
+ */
+static inline __always_inline userptr_t
+UACCESS_INLINE ( efi, phys_to_user ) ( unsigned long phys_addr ) {
+ return phys_addr;
+}
+
+/**
+ * Convert user buffer to physical address
+ *
+ * @v userptr User pointer
+ * @v offset Offset from user pointer
+ * @ret phys_addr Physical address
+ */
+static inline __always_inline unsigned long
+UACCESS_INLINE ( efi, user_to_phys ) ( userptr_t userptr, off_t offset ) {
+ return ( userptr + offset );
+}
+
+static inline __always_inline userptr_t
+UACCESS_INLINE ( efi, virt_to_user ) ( volatile const void *addr ) {
+ return trivial_virt_to_user ( addr );
+}
+
+static inline __always_inline void *
+UACCESS_INLINE ( efi, user_to_virt ) ( userptr_t userptr, off_t offset ) {
+ return trivial_user_to_virt ( userptr, offset );
+}
+
+static inline __always_inline userptr_t
+UACCESS_INLINE ( efi, userptr_add ) ( userptr_t userptr, off_t offset ) {
+ return trivial_userptr_add ( userptr, offset );
+}
+
+static inline __always_inline void
+UACCESS_INLINE ( efi, memcpy_user ) ( userptr_t dest, off_t dest_off,
+ userptr_t src, off_t src_off,
+ size_t len ) {
+ trivial_memcpy_user ( dest, dest_off, src, src_off, len );
+}
+
+static inline __always_inline void
+UACCESS_INLINE ( efi, memmove_user ) ( userptr_t dest, off_t dest_off,
+ userptr_t src, off_t src_off,
+ size_t len ) {
+ trivial_memmove_user ( dest, dest_off, src, src_off, len );
+}
+
+static inline __always_inline void
+UACCESS_INLINE ( efi, memset_user ) ( userptr_t buffer, off_t offset,
+ int c, size_t len ) {
+ trivial_memset_user ( buffer, offset, c, len );
+}
+
+static inline __always_inline size_t
+UACCESS_INLINE ( efi, strlen_user ) ( userptr_t buffer, off_t offset ) {
+ return trivial_strlen_user ( buffer, offset );
+}
+
+static inline __always_inline off_t
+UACCESS_INLINE ( efi, memchr_user ) ( userptr_t buffer, off_t offset,
+ int c, size_t len ) {
+ return trivial_memchr_user ( buffer, offset, c, len );
+}
+
+#endif /* _GPXE_EFI_UACCESS_H */
diff --git a/gpxe/src/include/gpxe/efi/efi_umalloc.h b/gpxe/src/include/gpxe/efi/efi_umalloc.h
new file mode 100644
index 00000000..def17b2d
--- /dev/null
+++ b/gpxe/src/include/gpxe/efi/efi_umalloc.h
@@ -0,0 +1,16 @@
+#ifndef _GPXE_EFI_UMALLOC_H
+#define _GPXE_EFI_UMALLOC_H
+
+/** @file
+ *
+ * gPXE user memory allocation API for EFI
+ *
+ */
+
+#ifdef UMALLOC_EFI
+#define UMALLOC_PREFIX_efi
+#else
+#define UMALLOC_PREFIX_efi __efi_
+#endif
+
+#endif /* _GPXE_EFI_UMALLOC_H */
diff --git a/gpxe/src/include/gpxe/efi/import.pl b/gpxe/src/include/gpxe/efi/import.pl
new file mode 100755
index 00000000..16993944
--- /dev/null
+++ b/gpxe/src/include/gpxe/efi/import.pl
@@ -0,0 +1,75 @@
+#!/usr/bin/perl -w
+
+use File::Spec::Functions qw ( :ALL );
+use File::Find;
+use File::Path;
+use FindBin;
+use strict;
+use warnings;
+
+sub try_import_file {
+ my $gpxedir = shift;
+ my $edkdirs = shift;
+ my $filename = shift;
+
+ # Skip everything except headers
+ return unless $filename =~ /\.h$/;
+ print "$filename...";
+
+ my $outfile = catfile ( $gpxedir, $filename );
+ foreach my $edkdir ( @$edkdirs ) {
+ my $infile = catfile ( $edkdir, $filename );
+ if ( -e $infile ) {
+ # We have found a matching source file - import it
+ print "$infile\n";
+ open my $infh, "<$infile" or die "Could not open $infile: $!\n";
+ ( undef, my $outdir, undef ) = splitpath ( $outfile );
+ mkpath ( $outdir );
+ open my $outfh, ">$outfile" or die "Could not open $outfile: $!\n";
+ my @dependencies = ();
+ while ( <$infh> ) {
+ # Strip CR and trailing whitespace
+ s/\r//g;
+ s/\s*$//g;
+ chomp;
+ # Update include lines, and record included files
+ if ( s/^\#include\s+[<\"](\S+)[>\"]/\#include <gpxe\/efi\/$1>/ ) {
+ push @dependencies, $1;
+ }
+ print $outfh "$_\n";
+ }
+ close $outfh;
+ close $infh;
+ # Recurse to handle any included files that we don't already have
+ foreach my $dependency ( @dependencies ) {
+ if ( ! -e catfile ( $gpxedir, $dependency ) ) {
+ print "...following dependency on $dependency\n";
+ try_import_file ( $gpxedir, $edkdirs, $dependency );
+ }
+ }
+ return;
+ }
+ }
+ print "no equivalent found\n";
+}
+
+# Identify edk import directories
+die "Syntax $0 /path/to/edk2/edk2\n" unless @ARGV == 1;
+my $edktop = shift;
+die "Directory \"$edktop\" does not appear to contain the EFI EDK2\n"
+ unless -e catfile ( $edktop, "MdePkg" );
+my $edkdirs = [ catfile ( $edktop, "MdePkg/Include" ),
+ catfile ( $edktop, "IntelFrameworkPkg/Include" ) ];
+
+# Identify gPXE EFI includes directory
+my $gpxedir = $FindBin::Bin;
+die "Directory \"$gpxedir\" does not appear to contain the gPXE EFI includes\n"
+ unless -e catfile ( $gpxedir, "../../../include/gpxe/efi" );
+
+print "Importing EFI headers into $gpxedir\nfrom ";
+print join ( "\n and ", @$edkdirs )."\n";
+
+# Import headers
+find ( { wanted => sub {
+ try_import_file ( $gpxedir, $edkdirs, abs2rel ( $_, $gpxedir ) );
+}, no_chdir => 1 }, $gpxedir );
diff --git a/gpxe/src/include/gpxe/errfile.h b/gpxe/src/include/gpxe/errfile.h
index ca0abebf..c851c7d5 100644
--- a/gpxe/src/include/gpxe/errfile.h
+++ b/gpxe/src/include/gpxe/errfile.h
@@ -106,10 +106,12 @@
#define ERRFILE_e1000_hw ( ERRFILE_DRIVER | 0x00490000 )
#define ERRFILE_mtnic ( ERRFILE_DRIVER | 0x004a0000 )
#define ERRFILE_phantom ( ERRFILE_DRIVER | 0x004b0000 )
+#define ERRFILE_ne2k_isa ( ERRFILE_DRIVER | 0x004c0000 )
#define ERRFILE_scsi ( ERRFILE_DRIVER | 0x00700000 )
#define ERRFILE_arbel ( ERRFILE_DRIVER | 0x00710000 )
#define ERRFILE_hermon ( ERRFILE_DRIVER | 0x00720000 )
+#define ERRFILE_linda ( ERRFILE_DRIVER | 0x00730000 )
#define ERRFILE_aoe ( ERRFILE_NET | 0x00000000 )
#define ERRFILE_arp ( ERRFILE_NET | 0x00010000 )
@@ -134,11 +136,14 @@
#define ERRFILE_netdev_settings ( ERRFILE_NET | 0x00140000 )
#define ERRFILE_dhcppkt ( ERRFILE_NET | 0x00150000 )
#define ERRFILE_slam ( ERRFILE_NET | 0x00160000 )
+#define ERRFILE_ib_sma ( ERRFILE_NET | 0x00170000 )
+#define ERRFILE_ib_packet ( ERRFILE_NET | 0x00180000 )
#define ERRFILE_image ( ERRFILE_IMAGE | 0x00000000 )
#define ERRFILE_elf ( ERRFILE_IMAGE | 0x00010000 )
#define ERRFILE_script ( ERRFILE_IMAGE | 0x00020000 )
#define ERRFILE_segment ( ERRFILE_IMAGE | 0x00030000 )
+#define ERRFILE_efi_image ( ERRFILE_IMAGE | 0x00040000 )
#define ERRFILE_asn1 ( ERRFILE_OTHER | 0x00000000 )
#define ERRFILE_chap ( ERRFILE_OTHER | 0x00010000 )
@@ -156,6 +161,8 @@
#define ERRFILE_tls ( ERRFILE_OTHER | 0x000d0000 )
#define ERRFILE_ifmgmt ( ERRFILE_OTHER | 0x000e0000 )
#define ERRFILE_iscsiboot ( ERRFILE_OTHER | 0x000f0000 )
+#define ERRFILE_efi_pci ( ERRFILE_OTHER | 0x00100000 )
+#define ERRFILE_efi_snp ( ERRFILE_OTHER | 0x00110000 )
/** @} */
diff --git a/gpxe/src/include/gpxe/ethernet.h b/gpxe/src/include/gpxe/ethernet.h
index 158fe066..ff0fd6c1 100644
--- a/gpxe/src/include/gpxe/ethernet.h
+++ b/gpxe/src/include/gpxe/ethernet.h
@@ -9,6 +9,7 @@
#include <stdint.h>
#include <gpxe/netdevice.h>
+#include <gpxe/if_ether.h>
extern struct ll_protocol ethernet_protocol;
@@ -26,6 +27,7 @@ static inline struct net_device * alloc_etherdev ( size_t priv_size ) {
netdev = alloc_netdev ( priv_size );
if ( netdev ) {
netdev->ll_protocol = &ethernet_protocol;
+ netdev->max_pkt_len = ETH_FRAME_LEN;
}
return netdev;
}
diff --git a/gpxe/src/include/gpxe/features.h b/gpxe/src/include/gpxe/features.h
index 107ff085..e4d29213 100644
--- a/gpxe/src/include/gpxe/features.h
+++ b/gpxe/src/include/gpxe/features.h
@@ -46,6 +46,7 @@
#define DHCP_EB_FEATURE_PXE 0x21 /**< PXE format */
#define DHCP_EB_FEATURE_ELF 0x22 /**< ELF format */
#define DHCP_EB_FEATURE_COMBOOT 0x23 /**< COMBOOT format */
+#define DHCP_EB_FEATURE_EFI 0x24 /**< EFI format */
/** @} */
diff --git a/gpxe/src/include/gpxe/i2c.h b/gpxe/src/include/gpxe/i2c.h
index bfaee8fb..9d229546 100644
--- a/gpxe/src/include/gpxe/i2c.h
+++ b/gpxe/src/include/gpxe/i2c.h
@@ -8,6 +8,7 @@
*/
#include <stdint.h>
+#include <gpxe/bitbash.h>
/** An I2C device
*
@@ -15,10 +16,35 @@
* is accessed via an I2C interface.
*/
struct i2c_device {
- /** Address of this device */
- unsigned int address;
- /** Flag indicating a ten-bit address format */
- int tenbit;
+ /** Address of this device
+ *
+ * The actual address sent on the bus will look like
+ *
+ * <start> <device address> <word address overflow> <r/w>
+ *
+ * The "word address overflow" is any excess bits from the
+ * word address, i.e. any portion that does not fit within the
+ * defined word address length.
+ */
+ unsigned int dev_addr;
+ /** Device address length, in bytes
+ *
+ * This is the number of bytes that comprise the device
+ * address, defined to be the portion that terminates with the
+ * read/write bit.
+ */
+ unsigned int dev_addr_len;
+ /** Word adddress length, in bytes
+ *
+ * This is the number of bytes that comprise the word address,
+ * defined to be the portion that starts after the read/write
+ * bit and ends before the first data byte.
+ *
+ * For some devices, this length will be zero (i.e. the word
+ * address is contained entirely within the "word address
+ * overflow").
+ */
+ unsigned int word_addr_len;
};
/** An I2C interface
@@ -91,6 +117,9 @@ enum {
/** Delay required for bit-bashing operation */
#define I2C_UDELAY 5
+/** Maximum number of cycles to use when attempting a bus reset */
+#define I2C_RESET_MAX_CYCLES 32
+
/**
* Check presence of I2C device
*
@@ -106,6 +135,35 @@ static inline int i2c_check_presence ( struct i2c_interface *i2c,
return i2c->write ( i2c, i2cdev, 0, NULL, 0 );
}
-extern void init_i2c_bit_basher ( struct i2c_bit_basher *i2cbit );
+extern int init_i2c_bit_basher ( struct i2c_bit_basher *i2cbit,
+ struct bit_basher_operations *bash_op );
+
+/**
+ * Initialise generic I2C EEPROM device
+ *
+ * @v i2cdev I2C device
+ */
+static inline __always_inline void
+init_i2c_eeprom ( struct i2c_device *i2cdev, unsigned int dev_addr ) {
+ i2cdev->dev_addr = dev_addr;
+ i2cdev->dev_addr_len = 1;
+ i2cdev->word_addr_len = 1;
+}
+
+/**
+ * Initialise Atmel AT24C11
+ *
+ * @v i2cdev I2C device
+ */
+static inline __always_inline void
+init_at24c11 ( struct i2c_device *i2cdev ) {
+ /* This chip has no device address; it must be the only chip
+ * on the bus. The word address is contained entirely within
+ * the device address field.
+ */
+ i2cdev->dev_addr = 0;
+ i2cdev->dev_addr_len = 1;
+ i2cdev->word_addr_len = 0;
+}
#endif /* _GPXE_I2C_H */
diff --git a/gpxe/src/include/gpxe/ib_mad.h b/gpxe/src/include/gpxe/ib_mad.h
new file mode 100644
index 00000000..6c4e95b7
--- /dev/null
+++ b/gpxe/src/include/gpxe/ib_mad.h
@@ -0,0 +1,364 @@
+#ifndef _GPXE_IB_MAD_H
+#define _GPXE_IB_MAD_H
+
+/** @file
+ *
+ * Infiniband management datagrams
+ *
+ */
+
+#include <stdint.h>
+#include <gpxe/ib_packet.h>
+
+/*****************************************************************************
+ *
+ * Subnet management MADs
+ *
+ *****************************************************************************
+ */
+
+/** A subnet management header
+ *
+ * Defined in sections 14.2.1.1 and 14.2.1.2 of the IBA.
+ */
+struct ib_smp_hdr {
+ uint64_t mkey;
+ uint16_t slid;
+ uint16_t dlid;
+ uint8_t reserved[28];
+} __attribute__ (( packed ));
+
+/** Subnet management class version */
+#define IB_SMP_CLASS_VERSION 1
+
+/** Subnet management direction bit
+ *
+ * This bit resides in the "status" field in the MAD header.
+ */
+#define IB_SMP_STATUS_D_INBOUND 0x8000
+
+/* 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
+
+/**
+ * A Node Description attribute
+ *
+ * Defined in section 14.2.5.2 of the IBA
+ */
+struct ib_node_desc {
+ char node_string[64];
+} __attribute__ (( packed ));
+
+/** A Node Information attribute
+ *
+ * Defined in section 14.2.5.3 of the IBA.
+ */
+struct ib_node_info {
+ uint8_t base_version;
+ uint8_t class_version;
+ uint8_t node_type;
+ uint8_t num_ports;
+ uint8_t sys_guid[8];
+ uint8_t node_guid[8];
+ uint8_t port_guid[8];
+ uint16_t partition_cap;
+ uint16_t device_id;
+ uint32_t revision;
+ uint8_t local_port_num;
+ uint8_t vendor_id[3];
+} __attribute__ ((packed));
+
+#define IB_NODE_TYPE_HCA 0x01
+#define IB_NODE_TYPE_SWITCH 0x02
+#define IB_NODE_TYPE_ROUTER 0x03
+
+/** A GUID Information attribute
+ *
+ * Defined in section 14.2.5.5 of the IBA.
+ */
+struct ib_guid_info {
+ uint8_t guid[8][8];
+} __attribute__ (( packed ));
+
+/** A Port Information attribute
+ *
+ * Defined in section 14.2.5.6 of the IBA.
+ */
+struct ib_port_info {
+ uint64_t mkey;
+ uint8_t gid_prefix[8];
+ uint16_t lid;
+ uint16_t mastersm_lid;
+ uint32_t cap_mask;
+ uint16_t diag_code;
+ uint16_t mkey_lease_period;
+ uint8_t local_port_num;
+ uint8_t link_width_enabled;
+ uint8_t link_width_supported;
+ uint8_t link_width_active;
+ uint8_t link_speed_supported__port_state;
+ uint8_t port_phys_state__link_down_def_state;
+ uint8_t mkey_prot_bits__lmc;
+ uint8_t link_speed_active__link_speed_enabled;
+ uint8_t neighbour_mtu__mastersm_sl;
+ uint8_t vl_cap__init_type;
+ uint8_t vl_high_limit;
+ uint8_t vl_arbitration_high_cap;
+ uint8_t vl_arbitration_low_cap;
+ uint8_t init_type_reply__mtu_cap;
+ uint8_t vl_stall_count__hoq_life;
+ uint8_t operational_vls__enforcement;
+ uint16_t mkey_violations;
+ uint16_t pkey_violations;
+ uint16_t qkey_violations;
+ uint8_t guid_cap;
+ uint8_t client_reregister__subnet_timeout;
+ uint8_t resp_time_value;
+ uint8_t local_phy_errors__overrun_errors;
+ uint16_t max_credit_hint;
+ uint32_t link_round_trip_latency;
+} __attribute__ (( packed ));
+
+#define IB_LINK_WIDTH_1X 0x01
+#define IB_LINK_WIDTH_4X 0x02
+#define IB_LINK_WIDTH_8X 0x04
+#define IB_LINK_WIDTH_12X 0x08
+
+#define IB_LINK_SPEED_SDR 0x01
+#define IB_LINK_SPEED_DDR 0x02
+#define IB_LINK_SPEED_QDR 0x04
+
+#define IB_PORT_STATE_DOWN 0x01
+#define IB_PORT_STATE_INIT 0x02
+#define IB_PORT_STATE_ARMED 0x03
+#define IB_PORT_STATE_ACTIVE 0x04
+
+#define IB_PORT_PHYS_STATE_SLEEP 0x01
+#define IB_PORT_PHYS_STATE_POLLING 0x02
+
+#define IB_MTU_256 0x01
+#define IB_MTU_512 0x02
+#define IB_MTU_1024 0x03
+#define IB_MTU_2048 0x04
+#define IB_MTU_4096 0x05
+
+#define IB_VL_0 0x01
+#define IB_VL_0_1 0x02
+#define IB_VL_0_3 0x03
+#define IB_VL_0_7 0x04
+#define IB_VL_0_14 0x05
+
+/** A Partition Key Table attribute
+ *
+ * Defined in section 14.2.5.7 of the IBA.
+ */
+struct ib_pkey_table {
+ uint16_t pkey[32];
+} __attribute__ (( packed ));
+
+/** A subnet management attribute */
+union ib_smp_data {
+ struct ib_node_desc node_desc;
+ struct ib_node_info node_info;
+ struct ib_guid_info guid_info;
+ struct ib_port_info port_info;
+ struct ib_pkey_table pkey_table;
+ uint8_t bytes[64];
+} __attribute__ (( packed ));
+
+/** A subnet management directed route path */
+struct ib_smp_dr_path {
+ uint8_t hops[64];
+} __attribute__ (( packed ));
+
+/** Subnet management MAD class-specific data */
+struct ib_smp_class_specific {
+ uint8_t hop_pointer;
+ uint8_t hop_count;
+} __attribute__ (( packed ));
+
+/*****************************************************************************
+ *
+ * Subnet administration MADs
+ *
+ *****************************************************************************
+ */
+
+struct ib_rmpp_hdr {
+ uint32_t raw[3];
+} __attribute__ (( packed ));
+
+struct ib_sa_hdr {
+ uint32_t sm_key[2];
+ uint16_t reserved;
+ uint16_t attrib_offset;
+ uint32_t comp_mask[2];
+} __attribute__ (( packed ));
+
+#define IB_SA_ATTR_MC_MEMBER_REC 0x38
+#define IB_SA_ATTR_PATH_REC 0x35
+
+struct ib_path_record {
+ uint32_t reserved0[2];
+ struct ib_gid dgid;
+ struct ib_gid sgid;
+ uint16_t dlid;
+ uint16_t slid;
+ uint32_t hop_limit__flow_label__raw_traffic;
+ uint32_t pkey__numb_path__reversible__tclass;
+ uint8_t reserved1;
+ uint8_t reserved__sl;
+ uint8_t mtu_selector__mtu;
+ uint8_t rate_selector__rate;
+ uint32_t preference__packet_lifetime__packet_lifetime_selector;
+ uint32_t reserved2[35];
+} __attribute__ (( packed ));
+
+#define IB_SA_PATH_REC_DGID (1<<2)
+#define IB_SA_PATH_REC_SGID (1<<3)
+
+struct ib_mc_member_record {
+ struct ib_gid mgid;
+ struct ib_gid port_gid;
+ uint32_t qkey;
+ uint16_t mlid;
+ uint8_t mtu_selector__mtu;
+ uint8_t tclass;
+ uint16_t pkey;
+ uint8_t rate_selector__rate;
+ uint8_t packet_lifetime_selector__packet_lifetime;
+ uint32_t sl__flow_label__hop_limit;
+ uint8_t scope__join_state;
+ uint8_t proxy_join__reserved;
+ uint16_t reserved0;
+ uint32_t reserved1[37];
+} __attribute__ (( packed ));
+
+#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)
+
+union ib_sa_data {
+ struct ib_path_record path_record;
+ struct ib_mc_member_record mc_member_record;
+} __attribute__ (( packed ));
+
+/*****************************************************************************
+ *
+ * MADs
+ *
+ *****************************************************************************
+ */
+
+/** Management datagram class_specific data */
+union ib_mad_class_specific {
+ uint16_t raw;
+ struct ib_smp_class_specific smp;
+} __attribute__ (( packed ));
+
+/** A management datagram common header
+ *
+ * Defined in section 13.4.2 of the IBA.
+ */
+struct ib_mad_hdr {
+ uint8_t base_version;
+ uint8_t mgmt_class;
+ uint8_t class_version;
+ uint8_t method;
+ uint16_t status;
+ union ib_mad_class_specific class_specific;
+ uint32_t tid[2];
+ uint16_t attr_id;
+ uint8_t reserved[2];
+ uint32_t attr_mod;
+} __attribute__ (( packed ));
+
+/* 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
+
+/* Status codes */
+#define IB_MGMT_STATUS_OK 0x0000
+#define IB_MGMT_STATUS_BAD_VERSION 0x0001
+#define IB_MGMT_STATUS_UNSUPPORTED_METHOD 0x0002
+#define IB_MGMT_STATUS_UNSUPPORTED_METHOD_ATTR 0x0003
+#define IB_MGMT_STATUS_INVALID_VALUE 0x0004
+
+/** A subnet management MAD */
+struct ib_mad_smp {
+ struct ib_mad_hdr mad_hdr;
+ struct ib_smp_hdr smp_hdr;
+ union ib_smp_data smp_data;
+ struct ib_smp_dr_path initial_path;
+ struct ib_smp_dr_path return_path;
+} __attribute__ (( packed ));
+
+/** A subnet administration MAD */
+struct ib_mad_sa {
+ struct ib_mad_hdr mad_hdr;
+ struct ib_rmpp_hdr rmpp_hdr;
+ struct ib_sa_hdr sa_hdr;
+ union ib_sa_data sa_data;
+} __attribute__ (( packed ));
+
+/** A management datagram */
+union ib_mad {
+ struct ib_mad_hdr hdr;
+ struct ib_mad_smp smp;
+ struct ib_mad_sa sa;
+ uint8_t bytes[256];
+} __attribute__ (( packed ));
+
+#endif /* _GPXE_IB_MAD_H */
diff --git a/gpxe/src/include/gpxe/ib_packet.h b/gpxe/src/include/gpxe/ib_packet.h
new file mode 100644
index 00000000..5374802c
--- /dev/null
+++ b/gpxe/src/include/gpxe/ib_packet.h
@@ -0,0 +1,147 @@
+#ifndef _GPXE_IB_PACKET_H
+#define _GPXE_IB_PACKET_H
+
+/** @file
+ *
+ * Infiniband packet format
+ *
+ */
+
+struct ib_device;
+struct ib_queue_pair;
+struct ib_address_vector;
+struct io_buffer;
+
+/** Half of an Infiniband Global Identifier */
+struct ib_gid_half {
+ uint8_t bytes[8];
+};
+
+/** An Infiniband Global Identifier */
+struct ib_gid {
+ union {
+ uint8_t bytes[16];
+ uint16_t words[8];
+ uint32_t dwords[4];
+ struct ib_gid_half half[2];
+ } u;
+};
+
+/** An Infiniband Local Route Header */
+struct ib_local_route_header {
+ /** Virtual lane and link version */
+ uint8_t vl__lver;
+ /** Service level and next link header */
+ uint8_t sl__lnh;
+ /** Destination LID */
+ uint16_t dlid;
+ /** Packet length */
+ uint16_t length;
+ /** Source LID */
+ uint16_t slid;
+} __attribute__ (( packed ));
+
+/** Infiniband virtual lanes */
+enum ib_vl {
+ IB_VL_DEFAULT = 0,
+ IB_VL_SMP = 15,
+};
+
+/** An Infiniband Link Next Header value */
+enum ib_lnh {
+ IB_LNH_RAW = 0,
+ IB_LNH_IPv6 = 1,
+ IB_LNH_BTH = 2,
+ IB_LNH_GRH = 3
+};
+
+/** Default Infiniband LID */
+#define IB_LID_NONE 0xffff
+
+/** Test for multicast LID */
+#define IB_LID_MULTICAST( lid ) ( ( (lid) >= 0xc000 ) && ( (lid) <= 0xfffe ) )
+
+/** An Infiniband Global Route Header */
+struct ib_global_route_header {
+ /** IP version, traffic class, and flow label
+ *
+ * 4 bits : Version of the GRH
+ * 8 bits : Traffic class
+ * 20 bits : Flow label
+ */
+ uint32_t ipver__tclass__flowlabel;
+ /** Payload length */
+ uint16_t paylen;
+ /** Next header */
+ uint8_t nxthdr;
+ /** Hop limit */
+ uint8_t hoplmt;
+ /** Source GID */
+ struct ib_gid sgid;
+ /** Destiniation GID */
+ struct ib_gid dgid;
+} __attribute__ (( packed ));
+
+#define IB_GRH_IPVER_IPv6 0x06
+#define IB_GRH_NXTHDR_IBA 0x1b
+
+/** An Infiniband Base Transport Header */
+struct ib_base_transport_header {
+ /** Opcode */
+ uint8_t opcode;
+ /** Transport header version, pad count, migration and solicitation */
+ uint8_t se__m__padcnt__tver;
+ /** Partition key */
+ uint16_t pkey;
+ /** Destination queue pair */
+ uint32_t dest_qp;
+ /** Packet sequence number and acknowledge request */
+ uint32_t ack__psn;
+} __attribute__ (( packed ));
+
+/** An Infiniband BTH opcode */
+enum ib_bth_opcode {
+ BTH_OPCODE_UD_SEND = 0x64,
+};
+
+/** Default Infiniband partition key */
+#define IB_PKEY_NONE 0xffff
+
+/** Subnet management queue pair number */
+#define IB_QPN_SMP 0
+
+/** An Infiniband Datagram Extended Transport Header */
+struct ib_datagram_extended_transport_header {
+ /** Queue key */
+ uint32_t qkey;
+ /** Source queue pair */
+ uint32_t src_qp;
+} __attribute__ (( packed ));
+
+/** All known IB header formats */
+union ib_headers {
+ struct ib_local_route_header lrh;
+ struct {
+ struct ib_local_route_header lrh;
+ struct ib_global_route_header grh;
+ struct ib_base_transport_header bth;
+ struct ib_datagram_extended_transport_header deth;
+ } __attribute__ (( packed )) lrh__grh__bth__deth;
+ struct {
+ struct ib_local_route_header lrh;
+ struct ib_base_transport_header bth;
+ struct ib_datagram_extended_transport_header deth;
+ } __attribute__ (( packed )) lrh__bth__deth;
+} __attribute__ (( packed ));
+
+/** Maximum size required for IB headers */
+#define IB_MAX_HEADER_SIZE sizeof ( union ib_headers )
+
+extern int ib_push ( struct ib_device *ibdev, struct io_buffer *iobuf,
+ struct ib_queue_pair *qp, size_t payload_len,
+ const struct ib_address_vector *av );
+extern int ib_pull ( struct ib_device *ibdev, struct io_buffer *iobuf,
+ struct ib_queue_pair **qp, size_t *payload_len,
+ struct ib_address_vector *av );
+
+#endif /* _GPXE_IB_PACKET_H */
diff --git a/gpxe/src/include/gpxe/ib_sma.h b/gpxe/src/include/gpxe/ib_sma.h
new file mode 100644
index 00000000..835ed4ea
--- /dev/null
+++ b/gpxe/src/include/gpxe/ib_sma.h
@@ -0,0 +1,63 @@
+#ifndef _GPXE_IB_SMA_H
+#define _GPXE_IB_SMA_H
+
+/** @file
+ *
+ * Infiniband Subnet Management Agent
+ *
+ */
+
+#include <gpxe/infiniband.h>
+#include <gpxe/process.h>
+
+/** Infiniband Subnet Management Agent operations */
+struct ib_sma_operations {
+ /** Set port information
+ *
+ * @v ibdev Infiniband device
+ * @v port_info New port information
+ */
+ int ( * set_port_info ) ( struct ib_device *ibdev,
+ const struct ib_port_info *port_info );
+};
+
+/** An Infiniband Subnet Management Agent */
+struct ib_sma {
+ /** Infiniband device */
+ struct ib_device *ibdev;
+ /** SMA operations */
+ struct ib_sma_operations *op;
+ /** SMA completion queue */
+ struct ib_completion_queue *cq;
+ /** SMA queue pair */
+ struct ib_queue_pair *qp;
+ /** Poll process */
+ struct process poll;
+};
+
+/** SMA payload size allocated for received packets */
+#define IB_SMA_PAYLOAD_LEN 2048
+
+/** SMA number of send WQEs
+ *
+ * This is a policy decision.
+ */
+#define IB_SMA_NUM_SEND_WQES 4
+
+/** SMA number of receive WQEs
+ *
+ * This is a policy decision.
+ */
+#define IB_SMA_NUM_RECV_WQES 2
+
+/** SMA number of completion queue entries
+ *
+ * This is a policy decision
+ */
+#define IB_SMA_NUM_CQES 8
+
+extern int ib_create_sma ( struct ib_sma *sma, struct ib_device *ibdev,
+ struct ib_sma_operations *op );
+extern void ib_destroy_sma ( struct ib_sma *sma );
+
+#endif /* _GPXE_IB_SMA_H */
diff --git a/gpxe/src/include/gpxe/ib_smc.h b/gpxe/src/include/gpxe/ib_smc.h
new file mode 100644
index 00000000..bb9020bf
--- /dev/null
+++ b/gpxe/src/include/gpxe/ib_smc.h
@@ -0,0 +1,18 @@
+#ifndef _GPXE_IB_SMC_H
+#define _GPXE_IB_SMC_H
+
+/** @file
+ *
+ * Infiniband Subnet Management Client
+ *
+ */
+
+#include <gpxe/infiniband.h>
+
+typedef int ( * ib_local_mad_t ) ( struct ib_device *ibdev,
+ union ib_mad *mad );
+
+extern int ib_smc_update ( struct ib_device *ibdev,
+ ib_local_mad_t local_mad );
+
+#endif /* _GPXE_IB_SMC_H */
diff --git a/gpxe/src/include/gpxe/infiniband.h b/gpxe/src/include/gpxe/infiniband.h
index f9e65348..1bb82401 100644
--- a/gpxe/src/include/gpxe/infiniband.h
+++ b/gpxe/src/include/gpxe/infiniband.h
@@ -10,6 +10,8 @@
#include <stdint.h>
#include <gpxe/refcnt.h>
#include <gpxe/device.h>
+#include <gpxe/ib_packet.h>
+#include <gpxe/ib_mad.h>
/** Subnet administrator QPN */
#define IB_SA_QPN 1
@@ -20,38 +22,9 @@
/** Subnet administrator queue key */
#define IB_GLOBAL_QKEY 0x80010000UL
-/** An Infiniband Global Identifier */
-struct ib_gid {
- union {
- uint8_t bytes[16];
- uint16_t words[8];
- uint32_t dwords[4];
- } u;
-};
-
-/** An Infiniband Global Route Header */
-struct ib_global_route_header {
- /** IP version, traffic class, and flow label
- *
- * 4 bits : Version of the GRH
- * 8 bits : Traffic class
- * 20 bits : Flow label
- */
- uint32_t ipver_tclass_flowlabel;
- /** Payload length */
- uint16_t paylen;
- /** Next header */
- uint8_t nxthdr;
- /** Hop limit */
- uint8_t hoplmt;
- /** Source GID */
- struct ib_gid sgid;
- /** Destiniation GID */
- struct ib_gid dgid;
-} __attribute__ (( packed ));
-
struct ib_device;
struct ib_queue_pair;
+struct ib_address_vector;
struct ib_completion_queue;
/** An Infiniband Work Queue */
@@ -66,6 +39,8 @@ struct ib_work_queue {
struct list_head list;
/** Number of work queue entries */
unsigned int num_wqes;
+ /** Number of occupied work queue entries */
+ unsigned int fill;
/** Next work queue entry index
*
* This is the index of the next entry to be filled (i.e. the
@@ -80,8 +55,20 @@ struct ib_work_queue {
void *drv_priv;
};
+/** An Infiniband multicast GID */
+struct ib_multicast_gid {
+ /** List of multicast GIDs on this QP */
+ struct list_head list;
+ /** Multicast GID */
+ struct ib_gid gid;
+};
+
/** An Infiniband Queue Pair */
struct ib_queue_pair {
+ /** Containing Infiniband device */
+ struct ib_device *ibdev;
+ /** List of queue pairs on this Infiniband device */
+ struct list_head list;
/** Queue Pair Number */
unsigned long qpn;
/** Queue key */
@@ -90,6 +77,8 @@ struct ib_queue_pair {
struct ib_work_queue send;
/** Receive queue */
struct ib_work_queue recv;
+ /** List of multicast GIDs */
+ struct list_head mgids;
/** Driver private data */
void *drv_priv;
/** Queue owner private data */
@@ -101,6 +90,58 @@ enum ib_queue_pair_mods {
IB_MODIFY_QKEY = 0x0001,
};
+/** An Infiniband Address Vector */
+struct ib_address_vector {
+ /** Queue Pair Number */
+ unsigned long qpn;
+ /** Queue key
+ *
+ * Not specified for received packets.
+ */
+ unsigned long qkey;
+ /** Local ID */
+ unsigned int lid;
+ /** Rate
+ *
+ * Not specified for received packets.
+ */
+ unsigned int rate;
+ /** Service level */
+ unsigned int sl;
+ /** GID is present */
+ unsigned int gid_present;
+ /** GID, if present */
+ struct ib_gid gid;
+};
+
+/** Infiniband completion queue operations */
+struct ib_completion_queue_operations {
+ /**
+ * Complete Send WQE
+ *
+ * @v ibdev Infiniband device
+ * @v qp Queue pair
+ * @v iobuf I/O buffer
+ * @v rc Completion status code
+ */
+ void ( * complete_send ) ( struct ib_device *ibdev,
+ struct ib_queue_pair *qp,
+ struct io_buffer *iobuf, int rc );
+ /**
+ * Complete Receive WQE
+ *
+ * @v ibdev Infiniband device
+ * @v qp Queue pair
+ * @v av Address vector, or NULL
+ * @v iobuf I/O buffer
+ * @v rc Completion status code
+ */
+ void ( * complete_recv ) ( struct ib_device *ibdev,
+ struct ib_queue_pair *qp,
+ struct ib_address_vector *av,
+ struct io_buffer *iobuf, int rc );
+};
+
/** An Infiniband Completion Queue */
struct ib_completion_queue {
/** Completion queue number */
@@ -117,53 +158,12 @@ struct ib_completion_queue {
unsigned long next_idx;
/** List of work queues completing to this queue */
struct list_head work_queues;
+ /** Completion queue operations */
+ struct ib_completion_queue_operations *op;
/** Driver private data */
void *drv_priv;
};
-/** An Infiniband completion */
-struct ib_completion {
- /** Syndrome
- *
- * If non-zero, then the completion is in error.
- */
- unsigned int syndrome;
- /** Length */
- size_t len;
-};
-
-/** An Infiniband completion handler
- *
- * @v ibdev Infiniband device
- * @v qp Queue pair
- * @v completion Completion
- * @v iobuf I/O buffer
- */
-typedef void ( * ib_completer_t ) ( struct ib_device *ibdev,
- struct ib_queue_pair *qp,
- struct ib_completion *completion,
- struct io_buffer *iobuf );
-
-/** An Infiniband Address Vector */
-struct ib_address_vector {
- /** Destination Queue Pair */
- unsigned int dest_qp;
- /** Queue key */
- unsigned long qkey;
- /** Destination Local ID */
- unsigned int dlid;
- /** Rate */
- unsigned int rate;
- /** Service level */
- unsigned int sl;
- /** GID is present */
- unsigned int gid_present;
- /** GID */
- struct ib_gid gid;
-};
-
-struct ib_mad_hdr;
-
/**
* Infiniband device operations
*
@@ -246,15 +246,12 @@ struct ib_device_operations {
*
* @v ibdev Infiniband device
* @v cq Completion queue
- * @v complete_send Send completion handler
- * @v complete_recv Receive completion handler
*
- * The completion handler takes ownership of the I/O buffer.
+ * The relevant completion handler (specified at completion
+ * queue creation time) takes ownership of the I/O buffer.
*/
void ( * poll_cq ) ( struct ib_device *ibdev,
- struct ib_completion_queue *cq,
- ib_completer_t complete_send,
- ib_completer_t complete_recv );
+ struct ib_completion_queue *cq );
/**
* Poll event queue
*
@@ -293,16 +290,6 @@ struct ib_device_operations {
void ( * mcast_detach ) ( struct ib_device *ibdev,
struct ib_queue_pair *qp,
struct ib_gid *gid );
- /**
- * Issue management datagram
- *
- * @v ibdev Infiniband device
- * @v mad Management datagram
- * @v len Length of management datagram
- * @ret rc Return status code
- */
- int ( * mad ) ( struct ib_device *ibdev, struct ib_mad_hdr *mad,
- size_t len );
};
/** An Infiniband device */
@@ -313,26 +300,42 @@ struct ib_device {
struct list_head list;
/** Underlying device */
struct device *dev;
+ /** List of queue pairs */
+ struct list_head qps;
/** Infiniband operations */
struct ib_device_operations *op;
/** Port number */
unsigned int port;
- /** Link state */
- int link_up;
+
+ /** Port state */
+ uint8_t port_state;
+ /** Link width */
+ uint8_t link_width;
+ /** Link speed */
+ uint8_t link_speed;
/** Port GID */
- struct ib_gid port_gid;
+ struct ib_gid gid;
+ /** Port LID */
+ uint16_t lid;
/** Subnet manager LID */
- unsigned long sm_lid;
+ uint16_t sm_lid;
+ /** Subnet manager SL */
+ uint8_t sm_sl;
/** Partition key */
- unsigned int pkey;
+ uint16_t pkey;
+
+ /** Outbound packet sequence number */
+ uint32_t psn;
+
/** Driver private data */
void *drv_priv;
/** Owner private data */
void *owner_priv;
};
-extern struct ib_completion_queue * ib_create_cq ( struct ib_device *ibdev,
- unsigned int num_cqes );
+extern struct ib_completion_queue *
+ib_create_cq ( struct ib_device *ibdev, unsigned int num_cqes,
+ struct ib_completion_queue_operations *op );
extern void ib_destroy_cq ( struct ib_device *ibdev,
struct ib_completion_queue *cq );
extern struct ib_queue_pair *
@@ -343,54 +346,47 @@ extern int ib_modify_qp ( struct ib_device *ibdev, struct ib_queue_pair *qp,
unsigned long mod_list, unsigned long qkey );
extern void ib_destroy_qp ( struct ib_device *ibdev,
struct ib_queue_pair *qp );
+extern struct ib_queue_pair * ib_find_qp_qpn ( struct ib_device *ibdev,
+ unsigned long qpn );
+extern struct ib_queue_pair * ib_find_qp_mgid ( struct ib_device *ibdev,
+ struct ib_gid *gid );
extern struct ib_work_queue * ib_find_wq ( struct ib_completion_queue *cq,
unsigned long qpn, int is_send );
+extern int ib_post_send ( struct ib_device *ibdev, struct ib_queue_pair *qp,
+ struct ib_address_vector *av,
+ struct io_buffer *iobuf );
+extern int ib_post_recv ( struct ib_device *ibdev, struct ib_queue_pair *qp,
+ struct io_buffer *iobuf );
+extern void ib_complete_send ( struct ib_device *ibdev,
+ struct ib_queue_pair *qp,
+ struct io_buffer *iobuf, int rc );
+extern void ib_complete_recv ( struct ib_device *ibdev,
+ struct ib_queue_pair *qp,
+ struct ib_address_vector *av,
+ struct io_buffer *iobuf, int rc );
+extern int ib_mcast_attach ( struct ib_device *ibdev, struct ib_queue_pair *qp,
+ struct ib_gid *gid );
+extern void ib_mcast_detach ( struct ib_device *ibdev,
+ struct ib_queue_pair *qp, struct ib_gid *gid );
extern struct ib_device * alloc_ibdev ( size_t priv_size );
extern int register_ibdev ( struct ib_device *ibdev );
extern void unregister_ibdev ( struct ib_device *ibdev );
extern void ib_link_state_changed ( struct ib_device *ibdev );
+extern struct list_head ib_devices;
-/**
- * Post send work queue entry
- *
- * @v ibdev Infiniband device
- * @v qp Queue pair
- * @v av Address vector
- * @v iobuf I/O buffer
- * @ret rc Return status code
- */
-static inline __attribute__ (( always_inline )) int
-ib_post_send ( struct ib_device *ibdev, struct ib_queue_pair *qp,
- struct ib_address_vector *av, struct io_buffer *iobuf ) {
- return ibdev->op->post_send ( ibdev, qp, av, iobuf );
-}
-
-/**
- * Post receive work queue entry
- *
- * @v ibdev Infiniband device
- * @v qp Queue pair
- * @v iobuf I/O buffer
- * @ret rc Return status code
- */
-static inline __attribute__ (( always_inline )) int
-ib_post_recv ( struct ib_device *ibdev, struct ib_queue_pair *qp,
- struct io_buffer *iobuf ) {
- return ibdev->op->post_recv ( ibdev, qp, iobuf );
-}
+/** Iterate over all network devices */
+#define for_each_ibdev( ibdev ) \
+ list_for_each_entry ( (ibdev), &ib_devices, list )
/**
* Poll completion queue
*
* @v ibdev Infiniband device
* @v cq Completion queue
- * @v complete_send Send completion handler
- * @v complete_recv Receive completion handler
*/
-static inline __attribute__ (( always_inline )) void
-ib_poll_cq ( struct ib_device *ibdev, struct ib_completion_queue *cq,
- ib_completer_t complete_send, ib_completer_t complete_recv ) {
- ibdev->op->poll_cq ( ibdev, cq, complete_send, complete_recv );
+static inline __always_inline void
+ib_poll_cq ( struct ib_device *ibdev, struct ib_completion_queue *cq ) {
+ ibdev->op->poll_cq ( ibdev, cq );
}
/**
@@ -399,7 +395,7 @@ ib_poll_cq ( struct ib_device *ibdev, struct ib_completion_queue *cq,
* @v ibdev Infiniband device
* @ret rc Return status code
*/
-static inline __attribute__ (( always_inline )) int
+static inline __always_inline int
ib_open ( struct ib_device *ibdev ) {
return ibdev->op->open ( ibdev );
}
@@ -409,49 +405,20 @@ ib_open ( struct ib_device *ibdev ) {
*
* @v ibdev Infiniband device
*/
-static inline __attribute__ (( always_inline )) void
+static inline __always_inline void
ib_close ( struct ib_device *ibdev ) {
ibdev->op->close ( ibdev );
}
/**
- * Attach to multicast group
- *
- * @v ibdev Infiniband device
- * @v qp Queue pair
- * @v gid Multicast GID
- * @ret rc Return status code
- */
-static inline __attribute__ (( always_inline )) int
-ib_mcast_attach ( struct ib_device *ibdev, struct ib_queue_pair *qp,
- struct ib_gid *gid ) {
- return ibdev->op->mcast_attach ( ibdev, qp, gid );
-}
-
-/**
- * Detach from multicast group
- *
- * @v ibdev Infiniband device
- * @v qp Queue pair
- * @v gid Multicast GID
- */
-static inline __attribute__ (( always_inline )) void
-ib_mcast_detach ( struct ib_device *ibdev, struct ib_queue_pair *qp,
- struct ib_gid *gid ) {
- ibdev->op->mcast_detach ( ibdev, qp, gid );
-}
-
-/**
- * Issue management datagram
+ * Check link state
*
* @v ibdev Infiniband device
- * @v mad Management datagram
- * @v len Length of management datagram
- * @ret rc Return status code
+ * @ret link_up Link is up
*/
-static inline __attribute__ (( always_inline )) int
-ib_mad ( struct ib_device *ibdev, struct ib_mad_hdr *mad, size_t len ) {
- return ibdev->op->mad ( ibdev, mad, len );
+static inline __always_inline int
+ib_link_ok ( struct ib_device *ibdev ) {
+ return ( ibdev->port_state == IB_PORT_STATE_ACTIVE );
}
/**
@@ -460,7 +427,7 @@ ib_mad ( struct ib_device *ibdev, struct ib_mad_hdr *mad, size_t len ) {
* @v ibdev Infiniband device
* @ret ibdev Infiniband device
*/
-static inline __attribute__ (( always_inline )) struct ib_device *
+static inline __always_inline struct ib_device *
ibdev_get ( struct ib_device *ibdev ) {
ref_get ( &ibdev->refcnt );
return ibdev;
@@ -471,7 +438,7 @@ ibdev_get ( struct ib_device *ibdev ) {
*
* @v ibdev Infiniband device
*/
-static inline __attribute__ (( always_inline )) void
+static inline __always_inline void
ibdev_put ( struct ib_device *ibdev ) {
ref_put ( &ibdev->refcnt );
}
@@ -482,7 +449,7 @@ ibdev_put ( struct ib_device *ibdev ) {
* @v wq Work queue
* @v priv Private data
*/
-static inline __attribute__ (( always_inline )) void
+static inline __always_inline void
ib_wq_set_drvdata ( struct ib_work_queue *wq, void *priv ) {
wq->drv_priv = priv;
}
@@ -493,7 +460,7 @@ ib_wq_set_drvdata ( struct ib_work_queue *wq, void *priv ) {
* @v wq Work queue
* @ret priv Private data
*/
-static inline __attribute__ (( always_inline )) void *
+static inline __always_inline void *
ib_wq_get_drvdata ( struct ib_work_queue *wq ) {
return wq->drv_priv;
}
@@ -504,7 +471,7 @@ ib_wq_get_drvdata ( struct ib_work_queue *wq ) {
* @v qp Queue pair
* @v priv Private data
*/
-static inline __attribute__ (( always_inline )) void
+static inline __always_inline void
ib_qp_set_drvdata ( struct ib_queue_pair *qp, void *priv ) {
qp->drv_priv = priv;
}
@@ -515,7 +482,7 @@ ib_qp_set_drvdata ( struct ib_queue_pair *qp, void *priv ) {
* @v qp Queue pair
* @ret priv Private data
*/
-static inline __attribute__ (( always_inline )) void *
+static inline __always_inline void *
ib_qp_get_drvdata ( struct ib_queue_pair *qp ) {
return qp->drv_priv;
}
@@ -526,7 +493,7 @@ ib_qp_get_drvdata ( struct ib_queue_pair *qp ) {
* @v qp Queue pair
* @v priv Private data
*/
-static inline __attribute__ (( always_inline )) void
+static inline __always_inline void
ib_qp_set_ownerdata ( struct ib_queue_pair *qp, void *priv ) {
qp->owner_priv = priv;
}
@@ -537,7 +504,7 @@ ib_qp_set_ownerdata ( struct ib_queue_pair *qp, void *priv ) {
* @v qp Queue pair
* @ret priv Private data
*/
-static inline __attribute__ (( always_inline )) void *
+static inline __always_inline void *
ib_qp_get_ownerdata ( struct ib_queue_pair *qp ) {
return qp->owner_priv;
}
@@ -548,7 +515,7 @@ ib_qp_get_ownerdata ( struct ib_queue_pair *qp ) {
* @v cq Completion queue
* @v priv Private data
*/
-static inline __attribute__ (( always_inline )) void
+static inline __always_inline void
ib_cq_set_drvdata ( struct ib_completion_queue *cq, void *priv ) {
cq->drv_priv = priv;
}
@@ -559,7 +526,7 @@ ib_cq_set_drvdata ( struct ib_completion_queue *cq, void *priv ) {
* @v cq Completion queue
* @ret priv Private data
*/
-static inline __attribute__ (( always_inline )) void *
+static inline __always_inline void *
ib_cq_get_drvdata ( struct ib_completion_queue *cq ) {
return cq->drv_priv;
}
@@ -570,7 +537,7 @@ ib_cq_get_drvdata ( struct ib_completion_queue *cq ) {
* @v ibdev Infiniband device
* @v priv Private data
*/
-static inline __attribute__ (( always_inline )) void
+static inline __always_inline void
ib_set_drvdata ( struct ib_device *ibdev, void *priv ) {
ibdev->drv_priv = priv;
}
@@ -581,7 +548,7 @@ ib_set_drvdata ( struct ib_device *ibdev, void *priv ) {
* @v ibdev Infiniband device
* @ret priv Private data
*/
-static inline __attribute__ (( always_inline )) void *
+static inline __always_inline void *
ib_get_drvdata ( struct ib_device *ibdev ) {
return ibdev->drv_priv;
}
@@ -592,7 +559,7 @@ ib_get_drvdata ( struct ib_device *ibdev ) {
* @v ibdev Infiniband device
* @v priv Private data
*/
-static inline __attribute__ (( always_inline )) void
+static inline __always_inline void
ib_set_ownerdata ( struct ib_device *ibdev, void *priv ) {
ibdev->owner_priv = priv;
}
@@ -603,201 +570,9 @@ ib_set_ownerdata ( struct ib_device *ibdev, void *priv ) {
* @v ibdev Infiniband device
* @ret priv Private data
*/
-static inline __attribute__ (( always_inline )) void *
+static inline __always_inline void *
ib_get_ownerdata ( struct ib_device *ibdev ) {
return ibdev->owner_priv;
}
-/*****************************************************************************
- *
- * Management datagrams
- *
- * Portions Copyright (c) 2004 Mellanox Technologies Ltd. All rights
- * reserved.
- *
- */
-
-/* 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
-
-#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 ib_mad_hdr {
- uint8_t base_version;
- uint8_t mgmt_class;
- uint8_t class_version;
- uint8_t method;
- uint16_t status;
- uint16_t class_specific;
- uint32_t tid[2];
- uint16_t attr_id;
- uint16_t resv;
- uint32_t attr_mod;
-} __attribute__ (( packed ));
-
-struct ib_sa_hdr {
- uint32_t sm_key[2];
- uint16_t reserved;
- uint16_t attrib_offset;
- uint32_t comp_mask[2];
-} __attribute__ (( packed ));
-
-struct ib_rmpp_hdr {
- uint32_t raw[3];
-} __attribute__ (( packed ));
-
-struct ib_mad_data {
- struct ib_mad_hdr mad_hdr;
- uint8_t data[232];
-} __attribute__ (( packed ));
-
-struct ib_mad_guid_info {
- struct ib_mad_hdr mad_hdr;
- uint32_t mkey[2];
- uint32_t reserved[8];
- uint8_t gid_local[8];
-} __attribute__ (( packed ));
-
-struct ib_mad_port_info {
- struct ib_mad_hdr mad_hdr;
- uint32_t mkey[2];
- uint32_t reserved[8];
- uint32_t mkey2[2];
- uint8_t gid_prefix[8];
- uint16_t lid;
- uint16_t mastersm_lid;
- uint32_t cap_mask;
- uint16_t diag_code;
- uint16_t mkey_lease_period;
- uint8_t local_port_num;
- uint8_t link_width_enabled;
- uint8_t link_width_supported;
- uint8_t link_width_active;
- uint8_t port_state__link_speed_supported;
- uint8_t link_down_def_state__port_phys_state;
- uint8_t lmc__r1__mkey_prot_bits;
- uint8_t link_speed_enabled__link_speed_active;
-} __attribute__ (( packed ));
-
-struct ib_mad_pkey_table {
- struct ib_mad_hdr mad_hdr;
- uint32_t mkey[2];
- uint32_t reserved[8];
- uint16_t pkey[16][2];
-} __attribute__ (( packed ));
-
-struct ib_mad_path_record {
- struct ib_mad_hdr mad_hdr;
- struct ib_rmpp_hdr rmpp_hdr;
- struct ib_sa_hdr sa_hdr;
- uint32_t reserved0[2];
- struct ib_gid dgid;
- struct ib_gid sgid;
- uint16_t dlid;
- uint16_t slid;
- uint32_t hop_limit__flow_label__raw_traffic;
- uint32_t pkey__numb_path__reversible__tclass;
- uint8_t reserved1;
- uint8_t reserved__sl;
- uint8_t mtu_selector__mtu;
- uint8_t rate_selector__rate;
- uint32_t preference__packet_lifetime__packet_lifetime_selector;
- uint32_t reserved2[35];
-} __attribute__ (( packed ));
-
-struct ib_mad_mc_member_record {
- struct ib_mad_hdr mad_hdr;
- struct ib_rmpp_hdr rmpp_hdr;
- struct ib_sa_hdr sa_hdr;
- struct ib_gid mgid;
- struct ib_gid port_gid;
- uint32_t qkey;
- uint16_t mlid;
- uint8_t mtu_selector__mtu;
- uint8_t tclass;
- uint16_t pkey;
- uint8_t rate_selector__rate;
- uint8_t packet_lifetime_selector__packet_lifetime;
- uint32_t sl__flow_label__hop_limit;
- uint8_t scope__join_state;
- uint8_t proxy_join__reserved;
- uint16_t reserved0;
- uint32_t reserved1[37];
-} __attribute__ (( packed ));
-
-union ib_mad {
- struct ib_mad_hdr mad_hdr;
- struct ib_mad_data data;
- struct ib_mad_guid_info guid_info;
- struct ib_mad_port_info port_info;
- struct ib_mad_pkey_table pkey_table;
- struct ib_mad_path_record path_record;
- struct ib_mad_mc_member_record mc_member_record;
-} __attribute__ (( packed ));
-
#endif /* _GPXE_INFINIBAND_H */
diff --git a/gpxe/src/include/gpxe/init.h b/gpxe/src/include/gpxe/init.h
index d2b450d7..e0e9f9c8 100644
--- a/gpxe/src/include/gpxe/init.h
+++ b/gpxe/src/include/gpxe/init.h
@@ -63,6 +63,7 @@ struct startup_fn {
#define STARTUP_EARLY 01 /**< Early startup */
#define STARTUP_NORMAL 02 /**< Normal startup */
+#define STARTUP_LATE 03 /**< Late startup */
/** @} */
diff --git a/gpxe/src/include/gpxe/io.h b/gpxe/src/include/gpxe/io.h
new file mode 100644
index 00000000..ebb8ba30
--- /dev/null
+++ b/gpxe/src/include/gpxe/io.h
@@ -0,0 +1,504 @@
+#ifndef _GPXE_IO_H
+#define _GPXE_IO_H
+
+/** @file
+ *
+ * gPXE I/O API
+ *
+ * The I/O API provides methods for reading from and writing to
+ * memory-mapped and I/O-mapped devices.
+ *
+ * The standard methods (readl()/writel() etc.) do not strictly check
+ * the type of the address parameter; this is because traditional
+ * usage does not necessarily provide the correct pointer type. For
+ * example, code written for ISA devices at fixed I/O addresses (such
+ * as the keyboard controller) tend to use plain integer constants for
+ * the address parameter.
+ */
+
+#include <stdint.h>
+#include <gpxe/api.h>
+#include <config/ioapi.h>
+#include <gpxe/uaccess.h>
+
+/**
+ * Calculate static inline I/O API function name
+ *
+ * @v _prefix Subsystem prefix
+ * @v _api_func API function
+ * @ret _subsys_func Subsystem API function
+ */
+#define IOAPI_INLINE( _subsys, _api_func ) \
+ SINGLE_API_INLINE ( IOAPI_PREFIX_ ## _subsys, _api_func )
+
+/**
+ * Provide an I/O API implementation
+ *
+ * @v _prefix Subsystem prefix
+ * @v _api_func API function
+ * @v _func Implementing function
+ */
+#define PROVIDE_IOAPI( _subsys, _api_func, _func ) \
+ PROVIDE_SINGLE_API ( IOAPI_PREFIX_ ## _subsys, _api_func, _func )
+
+/**
+ * Provide a static inline I/O API implementation
+ *
+ * @v _prefix Subsystem prefix
+ * @v _api_func API function
+ */
+#define PROVIDE_IOAPI_INLINE( _subsys, _api_func ) \
+ PROVIDE_SINGLE_API_INLINE ( IOAPI_PREFIX_ ## _subsys, _api_func )
+
+/* Include all architecture-independent I/O API headers */
+#include <gpxe/efi/efi_io.h>
+
+/* Include all architecture-dependent I/O API headers */
+#include <bits/io.h>
+
+/**
+ * Wrap an I/O read
+ *
+ * @v _func I/O API function
+ * @v _type Data type
+ * @v io_addr I/O address
+ * @v _prefix Prefix for address in debug message
+ * @v _ndigits Number of hex digits for this data type
+ */
+#define IOAPI_READ( _func, _type, io_addr, _prefix, _ndigits ) ( { \
+ volatile _type *_io_addr = \
+ ( ( volatile _type * ) ( intptr_t ) (io_addr) ); \
+ _type _data = _func ( _io_addr ); \
+ DBGIO ( "[" _prefix " %08lx] => %0" #_ndigits "llx\n", \
+ io_to_bus ( _io_addr ), ( unsigned long long ) _data ); \
+ _data; } )
+
+/**
+ * Wrap an I/O write
+ *
+ * @v _func I/O API function
+ * @v _type Data type
+ * @v data Value to write
+ * @v io_addr I/O address
+ * @v _prefix Prefix for address in debug message
+ * @v _ndigits Number of hex digits for this data type
+ */
+#define IOAPI_WRITE( _func, _type, data, io_addr, _prefix, _ndigits ) do { \
+ volatile _type *_io_addr = \
+ ( ( volatile _type * ) ( intptr_t ) (io_addr) ); \
+ _type _data = (data); \
+ DBGIO ( "[" _prefix " %08lx] <= %0" #_ndigits "llx\n", \
+ io_to_bus ( _io_addr ), ( unsigned long long ) _data ); \
+ _func ( _data, _io_addr ); \
+ } while ( 0 )
+
+/**
+ * Wrap an I/O string read
+ *
+ * @v _func I/O API function
+ * @v _type Data type
+ * @v io_addr I/O address
+ * @v data Data buffer
+ * @v count Number of elements to read
+ * @v _prefix Prefix for address in debug message
+ * @v _ndigits Number of hex digits for this data type
+ */
+#define IOAPI_READS( _func, _type, io_addr, data, count, _prefix, _ndigits ) \
+ do { \
+ volatile _type *_io_addr = \
+ ( ( volatile _type * ) ( intptr_t ) (io_addr) ); \
+ void *_data_void = (data); /* Check data is a pointer */ \
+ _type * _data = ( ( _type * ) _data_void ); \
+ const _type * _dbg_data = _data; \
+ unsigned int _count = (count); \
+ unsigned int _dbg_count = _count; \
+ _func ( _io_addr, _data, _count ); \
+ DBGIO ( "[" _prefix " %08lx] =>", io_to_bus ( _io_addr ) ); \
+ while ( _dbg_count-- ) { \
+ DBGIO ( " %0" #_ndigits "llx", \
+ ( ( unsigned long long ) *(_dbg_data++) ) ); \
+ } \
+ DBGIO ( "\n" ); \
+ } while ( 0 )
+
+/**
+ * Wrap an I/O string write
+ *
+ * @v _func I/O API function
+ * @v _type Data type
+ * @v io_addr I/O address
+ * @v data Data buffer
+ * @v count Number of elements to write
+ * @v _prefix Prefix for address in debug message
+ * @v _ndigits Number of hex digits for this data type
+ */
+#define IOAPI_WRITES( _func, _type, io_addr, data, count, _prefix, _ndigits ) \
+ do { \
+ volatile _type *_io_addr = \
+ ( ( volatile _type * ) ( intptr_t ) (io_addr) ); \
+ const void *_data_void = (data); /* Check data is a pointer */ \
+ const _type * _data = ( ( const _type * ) _data_void ); \
+ const _type * _dbg_data = _data; \
+ unsigned int _count = (count); \
+ unsigned int _dbg_count = _count; \
+ DBGIO ( "[" _prefix " %08lx] <=", io_to_bus ( _io_addr ) ); \
+ while ( _dbg_count-- ) { \
+ DBGIO ( " %0" #_ndigits "llx", \
+ ( ( unsigned long long ) *(_dbg_data++) ) ); \
+ } \
+ DBGIO ( "\n" ); \
+ _func ( _io_addr, _data, _count ); \
+ } while ( 0 )
+
+/**
+ * Convert physical address to a bus address
+ *
+ * @v phys_addr Physical address
+ * @ret bus_addr Bus address
+ */
+unsigned long phys_to_bus ( unsigned long phys_addr );
+
+/**
+ * Convert bus address to a physical address
+ *
+ * @v bus_addr Bus address
+ * @ret phys_addr Physical address
+ */
+unsigned long bus_to_phys ( unsigned long bus_addr );
+
+/**
+ * Convert virtual address to a bus address
+ *
+ * @v addr Virtual address
+ * @ret bus_addr Bus address
+ */
+static inline __always_inline unsigned long
+virt_to_bus ( volatile const void *addr ) {
+ return phys_to_bus ( virt_to_phys ( addr ) );
+}
+
+/**
+ * Convert bus address to a virtual address
+ *
+ * @v bus_addr Bus address
+ * @ret addr Virtual address
+ *
+ * This operation is not available under all memory models.
+ */
+static inline __always_inline void * bus_to_virt ( unsigned long bus_addr ) {
+ return phys_to_virt ( bus_to_phys ( bus_addr ) );
+}
+
+/**
+ * Map bus address as an I/O address
+ *
+ * @v bus_addr Bus address
+ * @v len Length of region
+ * @ret io_addr I/O address
+ */
+void * ioremap ( unsigned long bus_addr, size_t len );
+
+/**
+ * Unmap I/O address
+ *
+ * @v io_addr I/O address
+ */
+void iounmap ( volatile const void *io_addr );
+
+/**
+ * Convert I/O address to bus address (for debug only)
+ *
+ * @v io_addr I/O address
+ * @ret bus_addr Bus address
+ */
+unsigned long io_to_bus ( volatile const void *io_addr );
+
+/**
+ * Read byte from memory-mapped device
+ *
+ * @v io_addr I/O address
+ * @ret data Value read
+ */
+uint8_t readb ( volatile uint8_t *io_addr );
+#define readb( io_addr ) IOAPI_READ ( readb, uint8_t, io_addr, "MEM", 2 )
+
+/**
+ * Read 16-bit word from memory-mapped device
+ *
+ * @v io_addr I/O address
+ * @ret data Value read
+ */
+uint16_t readw ( volatile uint16_t *io_addr );
+#define readw( io_addr ) IOAPI_READ ( readw, uint16_t, io_addr, "MEM", 4 )
+
+/**
+ * Read 32-bit dword from memory-mapped device
+ *
+ * @v io_addr I/O address
+ * @ret data Value read
+ */
+uint32_t readl ( volatile uint32_t *io_addr );
+#define readl( io_addr ) IOAPI_READ ( readl, uint32_t, io_addr, "MEM", 8 )
+
+/**
+ * Read 64-bit qword from memory-mapped device
+ *
+ * @v io_addr I/O address
+ * @ret data Value read
+ */
+uint64_t readq ( volatile uint64_t *io_addr );
+#define readq( io_addr ) IOAPI_READ ( readq, uint64_t, io_addr, "MEM", 16 )
+
+/**
+ * Write byte to memory-mapped device
+ *
+ * @v data Value to write
+ * @v io_addr I/O address
+ */
+void writeb ( uint8_t data, volatile uint8_t *io_addr );
+#define writeb( data, io_addr ) \
+ IOAPI_WRITE ( writeb, uint8_t, data, io_addr, "MEM", 2 )
+
+/**
+ * Write 16-bit word to memory-mapped device
+ *
+ * @v data Value to write
+ * @v io_addr I/O address
+ */
+void writew ( uint16_t data, volatile uint16_t *io_addr );
+#define writew( data, io_addr ) \
+ IOAPI_WRITE ( writew, uint16_t, data, io_addr, "MEM", 4 )
+
+/**
+ * Write 32-bit dword to memory-mapped device
+ *
+ * @v data Value to write
+ * @v io_addr I/O address
+ */
+void writel ( uint32_t data, volatile uint32_t *io_addr );
+#define writel( data, io_addr ) \
+ IOAPI_WRITE ( writel, uint32_t, data, io_addr, "MEM", 8 )
+
+/**
+ * Write 64-bit qword to memory-mapped device
+ *
+ * @v data Value to write
+ * @v io_addr I/O address
+ */
+void writeq ( uint64_t data, volatile uint64_t *io_addr );
+#define writeq( data, io_addr ) \
+ IOAPI_WRITE ( writeq, uint64_t, data, io_addr, "MEM", 16 )
+
+/**
+ * Read byte from I/O-mapped device
+ *
+ * @v io_addr I/O address
+ * @ret data Value read
+ */
+uint8_t inb ( volatile uint8_t *io_addr );
+#define inb( io_addr ) IOAPI_READ ( inb, uint8_t, io_addr, "IO", 2 )
+
+/**
+ * Read 16-bit word from I/O-mapped device
+ *
+ * @v io_addr I/O address
+ * @ret data Value read
+ */
+uint16_t inw ( volatile uint16_t *io_addr );
+#define inw( io_addr ) IOAPI_READ ( inw, uint16_t, io_addr, "IO", 4 )
+
+/**
+ * Read 32-bit dword from I/O-mapped device
+ *
+ * @v io_addr I/O address
+ * @ret data Value read
+ */
+uint32_t inl ( volatile uint32_t *io_addr );
+#define inl( io_addr ) IOAPI_READ ( inl, uint32_t, io_addr, "IO", 8 )
+
+/**
+ * Write byte to I/O-mapped device
+ *
+ * @v data Value to write
+ * @v io_addr I/O address
+ */
+void outb ( uint8_t data, volatile uint8_t *io_addr );
+#define outb( data, io_addr ) \
+ IOAPI_WRITE ( outb, uint8_t, data, io_addr, "IO", 2 )
+
+/**
+ * Write 16-bit word to I/O-mapped device
+ *
+ * @v data Value to write
+ * @v io_addr I/O address
+ */
+void outw ( uint16_t data, volatile uint16_t *io_addr );
+#define outw( data, io_addr ) \
+ IOAPI_WRITE ( outw, uint16_t, data, io_addr, "IO", 4 )
+
+/**
+ * Write 32-bit dword to I/O-mapped device
+ *
+ * @v data Value to write
+ * @v io_addr I/O address
+ */
+void outl ( uint32_t data, volatile uint32_t *io_addr );
+#define outl( data, io_addr ) \
+ IOAPI_WRITE ( outl, uint32_t, data, io_addr, "IO", 8 )
+
+/**
+ * Read bytes from I/O-mapped device
+ *
+ * @v io_addr I/O address
+ * @v data Data buffer
+ * @v count Number of bytes to read
+ */
+void insb ( volatile uint8_t *io_addr, uint8_t *data, unsigned int count );
+#define insb( io_addr, data, count ) \
+ IOAPI_READS ( insb, uint8_t, io_addr, data, count, "IO", 2 )
+
+/**
+ * Read 16-bit words from I/O-mapped device
+ *
+ * @v io_addr I/O address
+ * @v data Data buffer
+ * @v count Number of words to read
+ */
+void insw ( volatile uint16_t *io_addr, uint16_t *data, unsigned int count );
+#define insw( io_addr, data, count ) \
+ IOAPI_READS ( insw, uint16_t, io_addr, data, count, "IO", 4 )
+
+/**
+ * Read 32-bit words from I/O-mapped device
+ *
+ * @v io_addr I/O address
+ * @v data Data buffer
+ * @v count Number of words to read
+ */
+void insl ( volatile uint32_t *io_addr, uint32_t *data, unsigned int count );
+#define insl( io_addr, data, count ) \
+ IOAPI_READS ( insl, uint32_t, io_addr, data, count, "IO", 8 )
+
+/**
+ * Write bytes to I/O-mapped device
+ *
+ * @v io_addr I/O address
+ * @v data Data buffer
+ * @v count Number of bytes to write
+ */
+void outsb ( volatile uint8_t *io_addr, const uint8_t *data,
+ unsigned int count );
+#define outsb( io_addr, data, count ) \
+ IOAPI_WRITES ( outsb, uint8_t, io_addr, data, count, "IO", 2 )
+
+/**
+ * Write 16-bit words to I/O-mapped device
+ *
+ * @v io_addr I/O address
+ * @v data Data buffer
+ * @v count Number of words to write
+ */
+void outsw ( volatile uint16_t *io_addr, const uint16_t *data,
+ unsigned int count );
+#define outsw( io_addr, data, count ) \
+ IOAPI_WRITES ( outsw, uint16_t, io_addr, data, count, "IO", 4 )
+
+/**
+ * Write 32-bit words to I/O-mapped device
+ *
+ * @v io_addr I/O address
+ * @v data Data buffer
+ * @v count Number of words to write
+ */
+void outsl ( volatile uint32_t *io_addr, const uint32_t *data,
+ unsigned int count );
+#define outsl( io_addr, data, count ) \
+ IOAPI_WRITES ( outsl, uint32_t, io_addr, data, count, "IO", 8 )
+
+/**
+ * Slow down I/O
+ *
+ */
+void iodelay ( void );
+
+/**
+ * Read value from I/O-mapped device, slowly
+ *
+ * @v _func Function to use to read value
+ * @v data Value to write
+ * @v io_addr I/O address
+ */
+#define INX_P( _func, _type, io_addr ) ( { \
+ _type _data = _func ( (io_addr) ); \
+ iodelay(); \
+ _data; } )
+
+/**
+ * Read byte from I/O-mapped device
+ *
+ * @v io_addr I/O address
+ * @ret data Value read
+ */
+#define inb_p( io_addr ) INX_P ( inb, uint8_t, io_addr )
+
+/**
+ * Read 16-bit word from I/O-mapped device
+ *
+ * @v io_addr I/O address
+ * @ret data Value read
+ */
+#define inw_p( io_addr ) INX_P ( inw, uint16_t, io_addr )
+
+/**
+ * Read 32-bit dword from I/O-mapped device
+ *
+ * @v io_addr I/O address
+ * @ret data Value read
+ */
+#define inl_p( io_addr ) INX_P ( inl, uint32_t, io_addr )
+
+/**
+ * Write value to I/O-mapped device, slowly
+ *
+ * @v _func Function to use to write value
+ * @v data Value to write
+ * @v io_addr I/O address
+ */
+#define OUTX_P( _func, data, io_addr ) do { \
+ _func ( (data), (io_addr) ); \
+ iodelay(); \
+ } while ( 0 )
+
+/**
+ * Write byte to I/O-mapped device, slowly
+ *
+ * @v data Value to write
+ * @v io_addr I/O address
+ */
+#define outb_p( data, io_addr ) OUTX_P ( outb, data, io_addr )
+
+/**
+ * Write 16-bit word to I/O-mapped device, slowly
+ *
+ * @v data Value to write
+ * @v io_addr I/O address
+ */
+#define outw_p( data, io_addr ) OUTX_P ( outw, data, io_addr )
+
+/**
+ * Write 32-bit dword to I/O-mapped device, slowly
+ *
+ * @v data Value to write
+ * @v io_addr I/O address
+ */
+#define outl_p( data, io_addr ) OUTX_P ( outl, data, io_addr )
+
+/**
+ * Memory barrier
+ *
+ */
+void mb ( void );
+#define rmb() mb()
+#define wmb() mb()
+
+#endif /* _GPXE_IO_H */
diff --git a/gpxe/src/include/gpxe/iobuf.h b/gpxe/src/include/gpxe/iobuf.h
index ff787754..db7fa042 100644
--- a/gpxe/src/include/gpxe/iobuf.h
+++ b/gpxe/src/include/gpxe/iobuf.h
@@ -181,6 +181,24 @@ static inline size_t iob_tailroom ( struct io_buffer *iobuf ) {
return ( iobuf->end - iobuf->tail );
}
+/**
+ * Create a temporary I/O buffer
+ *
+ * @v iobuf I/O buffer
+ * @v data Data buffer
+ * @v len Length of data
+ * @v max_len Length of buffer
+ *
+ * It is sometimes useful to use the iob_xxx() methods on temporary
+ * data buffers.
+ */
+static inline void iob_populate ( struct io_buffer *iobuf,
+ void *data, size_t len, size_t max_len ) {
+ iobuf->head = iobuf->data = data;
+ iobuf->tail = ( data + len );
+ iobuf->end = ( data + max_len );
+}
+
extern struct io_buffer * __malloc alloc_iob ( size_t len );
extern void free_iob ( struct io_buffer *iobuf );
extern void iob_pad ( struct io_buffer *iobuf, size_t min_len );
diff --git a/gpxe/src/include/gpxe/ipoib.h b/gpxe/src/include/gpxe/ipoib.h
index bcbdc4c6..80adee5b 100644
--- a/gpxe/src/include/gpxe/ipoib.h
+++ b/gpxe/src/include/gpxe/ipoib.h
@@ -8,6 +8,9 @@
#include <gpxe/infiniband.h>
+/** IPoIB packet length */
+#define IPOIB_PKT_LEN 2048
+
/** IPoIB MAC address length */
#define IPOIB_ALEN 20
@@ -23,33 +26,30 @@ struct ipoib_mac {
} __attribute__ (( packed ));
/** IPoIB link-layer header length */
-#define IPOIB_HLEN 24
-
-/**
- * IPoIB link-layer header pseudo portion
- *
- * This part doesn't actually exist on the wire, but it provides a
- * convenient way to fit into the typical network device model.
- */
-struct ipoib_pseudo_hdr {
- /** Peer address */
- struct ipoib_mac peer;
-} __attribute__ (( packed ));
+#define IPOIB_HLEN 4
-/** IPoIB link-layer header real portion */
-struct ipoib_real_hdr {
+/** IPoIB link-layer header */
+struct ipoib_hdr {
/** Network-layer protocol */
uint16_t proto;
/** Reserved, must be zero */
- uint16_t reserved;
-} __attribute__ (( packed ));
-
-/** An IPoIB link-layer header */
-struct ipoib_hdr {
- /** Pseudo portion */
- struct ipoib_pseudo_hdr pseudo;
- /** Real portion */
- struct ipoib_real_hdr real;
+ union {
+ /** Reserved, must be zero */
+ uint16_t reserved;
+ /** Peer addresses
+ *
+ * We use these fields internally to represent the
+ * peer addresses using a lookup key. There simply
+ * isn't enough room in the IPoIB header to store
+ * literal source or destination MAC addresses.
+ */
+ struct {
+ /** Destination address key */
+ uint8_t dest;
+ /** Source address key */
+ uint8_t src;
+ } __attribute__ (( packed )) peer;
+ } __attribute__ (( packed )) u;
} __attribute__ (( packed ));
extern struct ll_protocol ipoib_protocol;
@@ -68,6 +68,7 @@ static inline struct net_device * alloc_ipoibdev ( size_t priv_size ) {
netdev = alloc_netdev ( priv_size );
if ( netdev ) {
netdev->ll_protocol = &ipoib_protocol;
+ netdev->max_pkt_len = IPOIB_PKT_LEN;
}
return netdev;
}
diff --git a/gpxe/src/include/gpxe/nap.h b/gpxe/src/include/gpxe/nap.h
new file mode 100644
index 00000000..f9ae3cf4
--- /dev/null
+++ b/gpxe/src/include/gpxe/nap.h
@@ -0,0 +1,54 @@
+#ifndef _GPXE_NAP_H
+#define _GPXE_NAP_H
+
+/** @file
+ *
+ * CPU sleeping
+ *
+ */
+
+#include <gpxe/api.h>
+#include <config/nap.h>
+
+/**
+ * Calculate static inline CPU sleeping API function name
+ *
+ * @v _prefix Subsystem prefix
+ * @v _api_func API function
+ * @ret _subsys_func Subsystem API function
+ */
+#define NAP_INLINE( _subsys, _api_func ) \
+ SINGLE_API_INLINE ( NAP_PREFIX_ ## _subsys, _api_func )
+
+/**
+ * Provide an CPU sleeping API implementation
+ *
+ * @v _prefix Subsystem prefix
+ * @v _api_func API function
+ * @v _func Implementing function
+ */
+#define PROVIDE_NAP( _subsys, _api_func, _func ) \
+ PROVIDE_SINGLE_API ( NAP_PREFIX_ ## _subsys, _api_func, _func )
+
+/**
+ * Provide a static inline CPU sleeping API implementation
+ *
+ * @v _prefix Subsystem prefix
+ * @v _api_func API function
+ */
+#define PROVIDE_NAP_INLINE( _subsys, _api_func ) \
+ PROVIDE_SINGLE_API_INLINE ( NAP_PREFIX_ ## _subsys, _api_func )
+
+/* Include all architecture-independent I/O API headers */
+#include <gpxe/null_nap.h>
+
+/* Include all architecture-dependent I/O API headers */
+#include <bits/nap.h>
+
+/**
+ * Sleep until next CPU interrupt
+ *
+ */
+void cpu_nap ( void );
+
+#endif /* _GPXE_NAP_H */
diff --git a/gpxe/src/include/gpxe/netdevice.h b/gpxe/src/include/gpxe/netdevice.h
index cdc8cbad..01b853f3 100644
--- a/gpxe/src/include/gpxe/netdevice.h
+++ b/gpxe/src/include/gpxe/netdevice.h
@@ -23,7 +23,7 @@ struct device;
#define MAX_LL_ADDR_LEN 20
/** Maximum length of a link-layer header */
-#define MAX_LL_HEADER_LEN 32
+#define MAX_LL_HEADER_LEN 6
/** Maximum length of a network-layer address */
#define MAX_NET_ADDR_LEN 4
@@ -79,34 +79,24 @@ struct ll_protocol {
* Add link-layer header
*
* @v iobuf I/O buffer
- * @v netdev Network device
- * @v net_protocol Network-layer protocol
* @v ll_dest Link-layer destination address
+ * @v ll_source Source link-layer address
+ * @v net_proto Network-layer protocol, in network-byte order
* @ret rc Return status code
- *
- * This method should prepend in the link-layer header
- * (e.g. the Ethernet DIX header).
*/
- int ( * push ) ( struct io_buffer *iobuf, struct net_device *netdev,
- struct net_protocol *net_protocol,
- const void *ll_dest );
+ int ( * push ) ( struct io_buffer *iobuf, const void *ll_dest,
+ const void *ll_source, uint16_t net_proto );
/**
* Remove link-layer header
*
- * @v iobuf I/O buffer
- * @v netdev Network device
- * @v net_proto Network-layer protocol, in network-byte order
- * @v ll_source Source link-layer address
- * @ret rc Return status code
- *
- * This method should strip off the link-layer header
- * (e.g. the Ethernet DIX header) and return the protocol and
- * source link-layer address. The method must not alter the
- * packet content, and may return the link-layer address as a
- * pointer to data within the packet.
+ * @v iobuf I/O buffer
+ * @ret ll_dest Link-layer destination address
+ * @ret ll_source Source link-layer address
+ * @ret net_proto Network-layer protocol, in network-byte order
+ * @ret rc Return status code
*/
- int ( * pull ) ( struct io_buffer *iobuf, struct net_device *netdev,
- uint16_t *net_proto, const void **ll_source );
+ int ( * pull ) ( struct io_buffer *iobuf, const void **ll_dest,
+ const void **ll_source, uint16_t *net_proto );
/**
* Transcribe link-layer address
*
@@ -120,6 +110,16 @@ struct ll_protocol {
* allocated.
*/
const char * ( * ntoa ) ( const void * ll_addr );
+ /**
+ * Hash multicast address
+ *
+ * @v af Address family
+ * @v net_addr Network-layer address
+ * @v ll_addr Link-layer address to fill in
+ * @ret rc Return status code
+ */
+ int ( * mc_hash ) ( unsigned int af, const void *net_addr,
+ void *ll_addr );
/** Link-layer protocol
*
* This is an ARPHRD_XXX constant, in network byte order.
@@ -193,16 +193,25 @@ struct net_device_operations {
void ( * irq ) ( struct net_device *netdev, int enable );
};
+/** Network device error */
+struct net_device_error {
+ /** Error status code */
+ int rc;
+ /** Error count */
+ unsigned int count;
+};
+
+/** Maximum number of unique errors that we will keep track of */
+#define NETDEV_MAX_UNIQUE_ERRORS 4
+
/** Network device statistics */
struct net_device_stats {
- /** Count of successfully completed transmissions */
- unsigned int tx_ok;
- /** Count of transmission errors */
- unsigned int tx_err;
- /** Count of successfully received packets */
- unsigned int rx_ok;
- /** Count of reception errors */
- unsigned int rx_err;
+ /** Count of successful completions */
+ unsigned int good;
+ /** Count of error completions */
+ unsigned int bad;
+ /** Error breakdowns */
+ struct net_device_error errors[NETDEV_MAX_UNIQUE_ERRORS];
};
/**
@@ -241,12 +250,19 @@ struct net_device {
* This is the bitwise-OR of zero or more NETDEV_XXX constants.
*/
unsigned int state;
+ /** Maximum packet length
+ *
+ * This length includes any link-layer headers.
+ */
+ size_t max_pkt_len;
/** TX packet queue */
struct list_head tx_queue;
/** RX packet queue */
struct list_head rx_queue;
- /** Device statistics */
- struct net_device_stats stats;
+ /** TX statistics */
+ struct net_device_stats tx_stats;
+ /** RX statistics */
+ struct net_device_stats rx_stats;
/** Configuration settings applicable to this device */
struct simple_settings settings;
diff --git a/gpxe/src/include/gpxe/null_nap.h b/gpxe/src/include/gpxe/null_nap.h
new file mode 100644
index 00000000..6dd0cda3
--- /dev/null
+++ b/gpxe/src/include/gpxe/null_nap.h
@@ -0,0 +1,21 @@
+#ifndef _GPXE_NULL_NAP_H
+#define _GPXE_NULL_NAP_H
+
+/** @file
+ *
+ * Null CPU sleeping
+ *
+ */
+
+#ifdef NAP_NULL
+#define NAP_PREFIX_null
+#else
+#define NAP_PREFIX_null __null_
+#endif
+
+static inline __always_inline void
+NAP_INLINE ( null, cpu_nap ) ( void ) {
+ /* Do nothing */
+}
+
+#endif /* _GPXE_NULL_NAP_H */
diff --git a/gpxe/src/include/gpxe/pci.h b/gpxe/src/include/gpxe/pci.h
index 90721574..1ccdb100 100644
--- a/gpxe/src/include/gpxe/pci.h
+++ b/gpxe/src/include/gpxe/pci.h
@@ -19,7 +19,7 @@
#include <stdint.h>
#include <gpxe/device.h>
#include <gpxe/tables.h>
-#include <pci_io.h>
+#include <gpxe/pci_io.h>
#include "pci_ids.h"
/*
diff --git a/gpxe/src/include/gpxe/pci_io.h b/gpxe/src/include/gpxe/pci_io.h
new file mode 100644
index 00000000..365166c8
--- /dev/null
+++ b/gpxe/src/include/gpxe/pci_io.h
@@ -0,0 +1,122 @@
+#ifndef _GPXE_PCI_IO_H
+#define _GPXE_PCI_IO_H
+
+/** @file
+ *
+ * PCI I/O API
+ *
+ */
+
+#include <stdint.h>
+#include <gpxe/api.h>
+#include <config/ioapi.h>
+
+/**
+ * Calculate static inline PCI I/O API function name
+ *
+ * @v _prefix Subsystem prefix
+ * @v _api_func API function
+ * @ret _subsys_func Subsystem API function
+ */
+#define PCIAPI_INLINE( _subsys, _api_func ) \
+ SINGLE_API_INLINE ( PCIAPI_PREFIX_ ## _subsys, _api_func )
+
+/**
+ * Provide a PCI I/O API implementation
+ *
+ * @v _prefix Subsystem prefix
+ * @v _api_func API function
+ * @v _func Implementing function
+ */
+#define PROVIDE_PCIAPI( _subsys, _api_func, _func ) \
+ PROVIDE_SINGLE_API ( PCIAPI_PREFIX_ ## _subsys, _api_func, _func )
+
+/**
+ * Provide a static inline PCI I/O API implementation
+ *
+ * @v _prefix Subsystem prefix
+ * @v _api_func API function
+ */
+#define PROVIDE_PCIAPI_INLINE( _subsys, _api_func ) \
+ PROVIDE_SINGLE_API_INLINE ( PCIAPI_PREFIX_ ## _subsys, _api_func )
+
+/* Include all architecture-independent I/O API headers */
+#include <gpxe/efi/efi_pci.h>
+
+/* Include all architecture-dependent I/O API headers */
+#include <bits/pci_io.h>
+
+/**
+ * Determine maximum PCI bus number within system
+ *
+ * @ret max_bus Maximum bus number
+ */
+int pci_max_bus ( void );
+
+/**
+ * Read byte from PCI configuration space
+ *
+ * @v pci PCI device
+ * @v where Location within PCI configuration space
+ * @v value Value read
+ * @ret rc Return status code
+ */
+int pci_read_config_byte ( struct pci_device *pci, unsigned int where,
+ uint8_t *value );
+
+/**
+ * Read 16-bit word from PCI configuration space
+ *
+ * @v pci PCI device
+ * @v where Location within PCI configuration space
+ * @v value Value read
+ * @ret rc Return status code
+ */
+int pci_read_config_word ( struct pci_device *pci, unsigned int where,
+ uint16_t *value );
+
+/**
+ * Read 32-bit dword from PCI configuration space
+ *
+ * @v pci PCI device
+ * @v where Location within PCI configuration space
+ * @v value Value read
+ * @ret rc Return status code
+ */
+int pci_read_config_dword ( struct pci_device *pci, unsigned int where,
+ uint32_t *value );
+
+/**
+ * Write byte to PCI configuration space
+ *
+ * @v pci PCI device
+ * @v where Location within PCI configuration space
+ * @v value Value to be written
+ * @ret rc Return status code
+ */
+int pci_write_config_byte ( struct pci_device *pci, unsigned int where,
+ uint8_t value );
+
+/**
+ * Write 16-bit word to PCI configuration space
+ *
+ * @v pci PCI device
+ * @v where Location within PCI configuration space
+ * @v value Value to be written
+ * @ret rc Return status code
+ */
+int pci_write_config_word ( struct pci_device *pci, unsigned int where,
+ uint16_t value );
+
+/**
+ * Write 32-bit dword to PCI configuration space
+ *
+ * @v pci PCI device
+ * @v where Location within PCI configuration space
+ * @v value Value to be written
+ * @ret rc Return status code
+ */
+int pci_write_config_dword ( struct pci_device *pci, unsigned int where,
+ uint32_t value );
+
+#endif /* _GPXE_PCI_IO_H */
diff --git a/gpxe/src/include/gpxe/retry.h b/gpxe/src/include/gpxe/retry.h
index ec57db9e..1e7fde4c 100644
--- a/gpxe/src/include/gpxe/retry.h
+++ b/gpxe/src/include/gpxe/retry.h
@@ -19,6 +19,8 @@
struct retry_timer {
/** List of active timers */
struct list_head list;
+ /** Timer is currently running */
+ unsigned int running;
/** Timeout value (in ticks) */
unsigned long timeout;
/** Minimum timeout value (in ticks)
@@ -31,10 +33,7 @@ struct retry_timer {
* A value of zero means "use default timeout."
*/
unsigned long max_timeout;
- /** Start time (in ticks)
- *
- * A start time of zero indicates a stopped timer.
- */
+ /** Start time (in ticks) */
unsigned long start;
/** Retry count */
unsigned int count;
@@ -74,7 +73,7 @@ static inline void start_timer_nodelay ( struct retry_timer *timer ) {
*/
static inline __attribute__ (( always_inline )) unsigned long
timer_running ( struct retry_timer *timer ) {
- return ( timer->start );
+ return ( timer->running );
}
#endif /* _GPXE_RETRY_H */
diff --git a/gpxe/src/include/gpxe/rotate.h b/gpxe/src/include/gpxe/rotate.h
new file mode 100644
index 00000000..42ec7196
--- /dev/null
+++ b/gpxe/src/include/gpxe/rotate.h
@@ -0,0 +1,27 @@
+#ifndef _GPXE_ROTATE_H
+#define _GPXE_ROTATE_H
+
+/** @file
+ *
+ * Bit operations
+ */
+
+#include <stdint.h>
+
+static inline uint32_t rol32 ( uint32_t data, unsigned int rotation ) {
+ return ( ( data << rotation ) | ( data >> ( 32 - rotation ) ) );
+}
+
+static inline uint32_t ror32 ( uint32_t data, unsigned int rotation ) {
+ return ( ( data >> rotation ) | ( data << ( 32 - rotation ) ) );
+}
+
+static inline uint64_t rol64 ( uint64_t data, unsigned int rotation ) {
+ return ( ( data << rotation ) | ( data >> ( 64 - rotation ) ) );
+}
+
+static inline uint64_t ror64 ( uint64_t data, unsigned int rotation ) {
+ return ( ( data >> rotation ) | ( data << ( 64 - rotation ) ) );
+}
+
+#endif /* _GPXE_ROTATE_H */
diff --git a/gpxe/src/include/gpxe/sanboot.h b/gpxe/src/include/gpxe/sanboot.h
new file mode 100644
index 00000000..ea26a356
--- /dev/null
+++ b/gpxe/src/include/gpxe/sanboot.h
@@ -0,0 +1,14 @@
+#ifndef _GPXE_SANBOOT_H
+#define _GPXE_SANBOOT_H
+
+#include <gpxe/tables.h>
+
+struct sanboot_protocol {
+ const char *prefix;
+ int ( * boot ) ( const char *root_path );
+};
+
+#define __sanboot_protocol \
+ __table ( struct sanboot_protocol, sanboot_protocols, 01 )
+
+#endif /* _GPXE_SANBOOT_H */
diff --git a/gpxe/src/include/gpxe/settings.h b/gpxe/src/include/gpxe/settings.h
index ee7dacee..37c01b05 100644
--- a/gpxe/src/include/gpxe/settings.h
+++ b/gpxe/src/include/gpxe/settings.h
@@ -72,6 +72,14 @@ struct settings {
struct refcnt *refcnt;
/** Name */
const char *name;
+ /** Tag magic
+ *
+ * This value will be ORed in to any numerical tags
+ * constructed by parse_setting_name(), and can be used to
+ * avoid e.g. attempting to retrieve the subnet mask from
+ * SMBIOS, or the system UUID from DHCP.
+ */
+ unsigned int tag_magic;
/** Parent settings block */
struct settings *parent;
/** Sibling settings blocks */
@@ -225,16 +233,19 @@ extern struct setting mac_setting __setting;
* @v op Settings block operations
* @v refcnt Containing object reference counter, or NULL
* @v name Settings block name
+ * @v tag_magic Tag magic
*/
static inline void settings_init ( struct settings *settings,
struct settings_operations *op,
struct refcnt *refcnt,
- const char *name ) {
+ const char *name,
+ unsigned int tag_magic ) {
INIT_LIST_HEAD ( &settings->siblings );
INIT_LIST_HEAD ( &settings->children );
settings->op = op;
settings->refcnt = refcnt;
settings->name = name;
+ settings->tag_magic = tag_magic;
}
/**
@@ -248,7 +259,7 @@ static inline void simple_settings_init ( struct simple_settings *simple,
struct refcnt *refcnt,
const char *name ) {
settings_init ( &simple->settings, &simple_settings_operations,
- refcnt, name );
+ refcnt, name, 0 );
}
/**
diff --git a/gpxe/src/include/gpxe/timer.h b/gpxe/src/include/gpxe/timer.h
index b7057225..862d87b3 100644
--- a/gpxe/src/include/gpxe/timer.h
+++ b/gpxe/src/include/gpxe/timer.h
@@ -1,41 +1,74 @@
-#ifndef GPXE_TIMER_H
-#define GPXE_TIMER_H
+#ifndef _GPXE_TIMER_H
+#define _GPXE_TIMER_H
-#include <stddef.h>
-#include <gpxe/tables.h>
+/** @file
+ *
+ * gPXE timer API
+ *
+ * The timer API provides udelay() for fixed delays, and currticks()
+ * for a monotonically increasing tick counter.
+ */
-typedef unsigned long tick_t;
+#include <gpxe/api.h>
+#include <config/timer.h>
-#define MSECS_IN_SEC (1000)
-#define USECS_IN_SEC (1000*1000)
-#define USECS_IN_MSEC (1000)
+/**
+ * Calculate static inline timer API function name
+ *
+ * @v _prefix Subsystem prefix
+ * @v _api_func API function
+ * @ret _subsys_func Subsystem API function
+ */
+#define TIMER_INLINE( _subsys, _api_func ) \
+ SINGLE_API_INLINE ( TIMER_PREFIX_ ## _subsys, _api_func )
-#define TICKS_PER_SEC USECS_IN_SEC
+/**
+ * Provide a timer API implementation
+ *
+ * @v _prefix Subsystem prefix
+ * @v _api_func API function
+ * @v _func Implementing function
+ */
+#define PROVIDE_TIMER( _subsys, _api_func, _func ) \
+ PROVIDE_SINGLE_API ( TIMER_PREFIX_ ## _subsys, _api_func, _func )
-extern tick_t currticks ( void );
+/**
+ * Provide a static inline timer API implementation
+ *
+ * @v _prefix Subsystem prefix
+ * @v _api_func API function
+ */
+#define PROVIDE_TIMER_INLINE( _subsys, _api_func ) \
+ PROVIDE_SINGLE_API_INLINE ( TIMER_PREFIX_ ## _subsys, _api_func )
-extern void generic_currticks_udelay ( unsigned int usecs );
+/* Include all architecture-independent I/O API headers */
+#include <gpxe/efi/efi_timer.h>
-/** A timer */
-struct timer {
- /** Initialise timer
- *
- * @ret rc Return status code
- */
- int ( * init ) ( void );
- /** Read current time
- *
- * @ret ticks Current time, in ticks
- */
- tick_t ( * currticks ) ( void );
- /** Delay
- *
- * @v usecs Time to delay, in microseconds
- */
- void ( * udelay ) ( unsigned int usecs );
-};
+/* Include all architecture-dependent I/O API headers */
+#include <bits/timer.h>
-#define __timer( order ) __table ( struct timer, timers, order )
+/**
+ * Delay for a fixed number of microseconds
+ *
+ * @v usecs Number of microseconds for which to delay
+ */
+void udelay ( unsigned long usecs );
-#endif /* GPXE_TIMER_H */
+/**
+ * Get current system time in ticks
+ *
+ * @ret ticks Current time, in ticks
+ */
+unsigned long currticks ( void );
+/**
+ * Get number of ticks per second
+ *
+ * @ret ticks_per_sec Number of ticks per second
+ */
+unsigned long ticks_per_sec ( void );
+
+/** Number of ticks per second */
+#define TICKS_PER_SEC ( ticks_per_sec() )
+
+#endif /* _GPXE_TIMER_H */
diff --git a/gpxe/src/include/gpxe/tls.h b/gpxe/src/include/gpxe/tls.h
index a8cf16ef..39109452 100644
--- a/gpxe/src/include/gpxe/tls.h
+++ b/gpxe/src/include/gpxe/tls.h
@@ -109,6 +109,22 @@ struct tls_cipherspec {
void *mac_secret;
};
+/** TLS pre-master secret */
+struct tls_pre_master_secret {
+ /** TLS version */
+ uint16_t version;
+ /** Random data */
+ uint8_t random[46];
+} __attribute__ (( packed ));
+
+/** TLS client random data */
+struct tls_client_random {
+ /** GMT Unix time */
+ uint32_t gmt_unix_time;
+ /** Random data */
+ uint8_t random[28];
+} __attribute__ (( packed ));
+
/** A TLS session */
struct tls_session {
/** Reference counter */
@@ -128,13 +144,13 @@ struct tls_session {
/** Next RX cipher specification */
struct tls_cipherspec rx_cipherspec_pending;
/** Premaster secret */
- uint8_t pre_master_secret[48];
+ struct tls_pre_master_secret pre_master_secret;
/** Master secret */
uint8_t master_secret[48];
/** Server random bytes */
uint8_t server_random[32];
/** Client random bytes */
- uint8_t client_random[32];
+ struct tls_client_random client_random;
/** MD5 context for handshake verification */
uint8_t handshake_md5_ctx[MD5_CTX_SIZE];
/** SHA1 context for handshake verification */
diff --git a/gpxe/src/include/gpxe/uaccess.h b/gpxe/src/include/gpxe/uaccess.h
index 05f89e03..33aaed18 100644
--- a/gpxe/src/include/gpxe/uaccess.h
+++ b/gpxe/src/include/gpxe/uaccess.h
@@ -19,9 +19,324 @@
*
*/
-#include <bits/uaccess.h>
+#include <stdint.h>
+#include <string.h>
+#include <gpxe/api.h>
+#include <config/ioapi.h>
+
+/**
+ * A pointer to a user buffer
+ *
+ */
+typedef unsigned long userptr_t;
/** Equivalent of NULL for user pointers */
#define UNULL ( ( userptr_t ) 0 )
+/**
+ * @defgroup uaccess_trivial Trivial user access API implementations
+ *
+ * User access API implementations that can be used by environments in
+ * which virtual addresses allow access to all of memory.
+ *
+ * @{
+ *
+ */
+
+/**
+ * Convert virtual address to user pointer
+ *
+ * @v addr Virtual address
+ * @ret userptr User pointer
+ */
+static inline __always_inline userptr_t
+trivial_virt_to_user ( volatile const void *addr ) {
+ return ( ( userptr_t ) addr );
+}
+
+/**
+ * Convert user pointer to virtual address
+ *
+ * @v userptr User pointer
+ * @v offset Offset from user pointer
+ * @ret addr Virtual address
+ *
+ * This operation is not available under all memory models.
+ */
+static inline __always_inline void *
+trivial_user_to_virt ( userptr_t userptr, off_t offset ) {
+ return ( ( void * ) userptr + offset );
+}
+
+/**
+ * Add offset to user pointer
+ *
+ * @v userptr User pointer
+ * @v offset Offset
+ * @ret userptr New pointer value
+ */
+static inline __always_inline userptr_t
+trivial_userptr_add ( userptr_t userptr, off_t offset ) {
+ return ( userptr + offset );
+}
+
+/**
+ * Copy data between user buffers
+ *
+ * @v dest Destination
+ * @v dest_off Destination offset
+ * @v src Source
+ * @v src_off Source offset
+ * @v len Length
+ */
+static inline __always_inline void
+trivial_memcpy_user ( userptr_t dest, off_t dest_off,
+ userptr_t src, off_t src_off, size_t len ) {
+ memcpy ( ( ( void * ) dest + dest_off ),
+ ( ( void * ) src + src_off ), len );
+}
+
+/**
+ * Copy data between user buffers, allowing for overlap
+ *
+ * @v dest Destination
+ * @v dest_off Destination offset
+ * @v src Source
+ * @v src_off Source offset
+ * @v len Length
+ */
+static inline __always_inline void
+trivial_memmove_user ( userptr_t dest, off_t dest_off,
+ userptr_t src, off_t src_off, size_t len ) {
+ memmove ( ( ( void * ) dest + dest_off ),
+ ( ( void * ) src + src_off ), len );
+}
+
+/**
+ * Fill user buffer with a constant byte
+ *
+ * @v buffer User buffer
+ * @v offset Offset within buffer
+ * @v c Constant byte with which to fill
+ * @v len Length
+ */
+static inline __always_inline void
+trivial_memset_user ( userptr_t buffer, off_t offset, int c, size_t len ) {
+ memset ( ( ( void * ) buffer + offset ), c, len );
+}
+
+/**
+ * Find length of NUL-terminated string in user buffer
+ *
+ * @v buffer User buffer
+ * @v offset Offset within buffer
+ * @ret len Length of string (excluding NUL)
+ */
+static inline __always_inline size_t
+trivial_strlen_user ( userptr_t buffer, off_t offset ) {
+ return strlen ( ( void * ) buffer + offset );
+}
+
+/**
+ * Find character in user buffer
+ *
+ * @v buffer User buffer
+ * @v offset Starting offset within buffer
+ * @v c Character to search for
+ * @v len Length of user buffer
+ * @ret offset Offset of character, or <0 if not found
+ */
+static inline __always_inline off_t
+trivial_memchr_user ( userptr_t buffer, off_t offset, int c, size_t len ) {
+ void *found;
+
+ found = memchr ( ( ( void * ) buffer + offset ), c, len );
+ return ( found ? ( found - ( void * ) buffer ) : -1 );
+}
+
+/** @} */
+
+/**
+ * Calculate static inline user access API function name
+ *
+ * @v _prefix Subsystem prefix
+ * @v _api_func API function
+ * @ret _subsys_func Subsystem API function
+ */
+#define UACCESS_INLINE( _subsys, _api_func ) \
+ SINGLE_API_INLINE ( UACCESS_PREFIX_ ## _subsys, _api_func )
+
+/**
+ * Provide an user access API implementation
+ *
+ * @v _prefix Subsystem prefix
+ * @v _api_func API function
+ * @v _func Implementing function
+ */
+#define PROVIDE_UACCESS( _subsys, _api_func, _func ) \
+ PROVIDE_SINGLE_API ( UACCESS_PREFIX_ ## _subsys, _api_func, _func )
+
+/**
+ * Provide a static inline user access API implementation
+ *
+ * @v _prefix Subsystem prefix
+ * @v _api_func API function
+ */
+#define PROVIDE_UACCESS_INLINE( _subsys, _api_func ) \
+ PROVIDE_SINGLE_API_INLINE ( UACCESS_PREFIX_ ## _subsys, _api_func )
+
+/* Include all architecture-independent user access API headers */
+#include <gpxe/efi/efi_uaccess.h>
+
+/* Include all architecture-dependent user access API headers */
+#include <bits/uaccess.h>
+
+/**
+ * Convert physical address to user pointer
+ *
+ * @v phys_addr Physical address
+ * @ret userptr User pointer
+ */
+userptr_t phys_to_user ( unsigned long phys_addr );
+
+/**
+ * Convert user pointer to physical address
+ *
+ * @v userptr User pointer
+ * @v offset Offset from user pointer
+ * @ret phys_addr Physical address
+ */
+unsigned long user_to_phys ( userptr_t userptr, off_t offset );
+
+/**
+ * Convert virtual address to user pointer
+ *
+ * @v addr Virtual address
+ * @ret userptr User pointer
+ */
+userptr_t virt_to_user ( volatile const void *addr );
+
+/**
+ * Convert user pointer to virtual address
+ *
+ * @v userptr User pointer
+ * @v offset Offset from user pointer
+ * @ret addr Virtual address
+ *
+ * This operation is not available under all memory models.
+ */
+void * user_to_virt ( userptr_t userptr, off_t offset );
+
+/**
+ * Add offset to user pointer
+ *
+ * @v userptr User pointer
+ * @v offset Offset
+ * @ret userptr New pointer value
+ */
+userptr_t userptr_add ( userptr_t userptr, off_t offset );
+
+/**
+ * Convert virtual address to a physical address
+ *
+ * @v addr Virtual address
+ * @ret phys_addr Physical address
+ */
+static inline __always_inline unsigned long
+virt_to_phys ( volatile const void *addr ) {
+ return user_to_phys ( virt_to_user ( addr ), 0 );
+}
+
+/**
+ * Convert physical address to a virtual address
+ *
+ * @v addr Virtual address
+ * @ret phys_addr Physical address
+ *
+ * This operation is not available under all memory models.
+ */
+static inline __always_inline void * phys_to_virt ( unsigned long phys_addr ) {
+ return user_to_virt ( phys_to_user ( phys_addr ), 0 );
+}
+
+/**
+ * Copy data between user buffers
+ *
+ * @v dest Destination
+ * @v dest_off Destination offset
+ * @v src Source
+ * @v src_off Source offset
+ * @v len Length
+ */
+void memcpy_user ( userptr_t dest, off_t dest_off,
+ userptr_t src, off_t src_off, size_t len );
+
+/**
+ * Copy data to user buffer
+ *
+ * @v dest Destination
+ * @v dest_off Destination offset
+ * @v src Source
+ * @v len Length
+ */
+static inline __always_inline void
+copy_to_user ( userptr_t dest, off_t dest_off, const void *src, size_t len ) {
+ memcpy_user ( dest, dest_off, virt_to_user ( src ), 0, len );
+}
+
+/**
+ * Copy data from user buffer
+ *
+ * @v dest Destination
+ * @v src Source
+ * @v src_off Source offset
+ * @v len Length
+ */
+static inline __always_inline void
+copy_from_user ( void *dest, userptr_t src, off_t src_off, size_t len ) {
+ memcpy_user ( virt_to_user ( dest ), 0, src, src_off, len );
+}
+
+/**
+ * Copy data between user buffers, allowing for overlap
+ *
+ * @v dest Destination
+ * @v dest_off Destination offset
+ * @v src Source
+ * @v src_off Source offset
+ * @v len Length
+ */
+void memmove_user ( userptr_t dest, off_t dest_off,
+ userptr_t src, off_t src_off, size_t len );
+
+/**
+ * Fill user buffer with a constant byte
+ *
+ * @v userptr User buffer
+ * @v offset Offset within buffer
+ * @v c Constant byte with which to fill
+ * @v len Length
+ */
+void memset_user ( userptr_t userptr, off_t offset, int c, size_t len );
+
+/**
+ * Find length of NUL-terminated string in user buffer
+ *
+ * @v userptr User buffer
+ * @v offset Offset within buffer
+ * @ret len Length of string (excluding NUL)
+ */
+size_t strlen_user ( userptr_t userptr, off_t offset );
+
+/**
+ * Find character in user buffer
+ *
+ * @v userptr User buffer
+ * @v offset Starting offset within buffer
+ * @v c Character to search for
+ * @v len Length of user buffer
+ * @ret offset Offset of character, or <0 if not found
+ */
+off_t memchr_user ( userptr_t userptr, off_t offset, int c, size_t len );
+
#endif /* _GPXE_UACCESS_H */
diff --git a/gpxe/src/include/gpxe/umalloc.h b/gpxe/src/include/gpxe/umalloc.h
index 49ec22b4..e6fc7bf0 100644
--- a/gpxe/src/include/gpxe/umalloc.h
+++ b/gpxe/src/include/gpxe/umalloc.h
@@ -8,10 +8,59 @@
*
*/
+#include <gpxe/api.h>
+#include <config/umalloc.h>
#include <gpxe/uaccess.h>
-extern userptr_t umalloc ( size_t size );
-extern userptr_t urealloc ( userptr_t ptr, size_t new_size );
-extern void ufree ( userptr_t ptr );
+/**
+ * Provide a user memory allocation API implementation
+ *
+ * @v _prefix Subsystem prefix
+ * @v _api_func API function
+ * @v _func Implementing function
+ */
+#define PROVIDE_UMALLOC( _subsys, _api_func, _func ) \
+ PROVIDE_SINGLE_API ( UMALLOC_PREFIX_ ## _subsys, _api_func, _func )
+
+/* Include all architecture-independent I/O API headers */
+#include <gpxe/efi/efi_umalloc.h>
+
+/* Include all architecture-dependent I/O API headers */
+#include <bits/umalloc.h>
+
+/**
+ * Reallocate external memory
+ *
+ * @v userptr Memory previously allocated by umalloc(), or UNULL
+ * @v new_size Requested size
+ * @ret userptr Allocated memory, or UNULL
+ *
+ * Calling realloc() with a new size of zero is a valid way to free a
+ * memory block.
+ */
+userptr_t urealloc ( userptr_t userptr, size_t new_size );
+
+/**
+ * Allocate external memory
+ *
+ * @v size Requested size
+ * @ret userptr Memory, or UNULL
+ *
+ * Memory is guaranteed to be aligned to a page boundary.
+ */
+static inline __always_inline userptr_t umalloc ( size_t size ) {
+ return urealloc ( UNULL, size );
+}
+
+/**
+ * Free external memory
+ *
+ * @v userptr Memory allocated by umalloc(), or UNULL
+ *
+ * If @c ptr is UNULL, no action is taken.
+ */
+static inline __always_inline void ufree ( userptr_t userptr ) {
+ urealloc ( userptr, 0 );
+}
#endif /* _GPXE_UMALLOC_H */
diff --git a/gpxe/src/include/gpxe/xfer.h b/gpxe/src/include/gpxe/xfer.h
index 9575bf69..e592fa38 100644
--- a/gpxe/src/include/gpxe/xfer.h
+++ b/gpxe/src/include/gpxe/xfer.h
@@ -149,8 +149,8 @@ extern int xfer_deliver_raw ( struct xfer_interface *xfer,
const void *data, size_t len );
extern int xfer_vprintf ( struct xfer_interface *xfer,
const char *format, va_list args );
-extern int xfer_printf ( struct xfer_interface *xfer,
- const char *format, ... );
+extern int __attribute__ (( format ( printf, 2, 3 ) ))
+xfer_printf ( struct xfer_interface *xfer, const char *format, ... );
extern int xfer_seek ( struct xfer_interface *xfer, off_t offset, int whence );
extern void ignore_xfer_close ( struct xfer_interface *xfer, int rc );
diff --git a/gpxe/src/include/nic.h b/gpxe/src/include/nic.h
index 65e4be71..186b2ea4 100644
--- a/gpxe/src/include/nic.h
+++ b/gpxe/src/include/nic.h
@@ -17,6 +17,7 @@
#include <gpxe/isa.h>
#include <gpxe/eisa.h>
#include <gpxe/mca.h>
+#include <gpxe/io.h>
#include "dhcp.h"
typedef enum {
diff --git a/gpxe/src/include/pxe_types.h b/gpxe/src/include/pxe_types.h
index e31af062..dd9092ef 100644
--- a/gpxe/src/include/pxe_types.h
+++ b/gpxe/src/include/pxe_types.h
@@ -7,9 +7,8 @@
*
*/
-#include "stdint.h"
-#include "pxe_addr.h" /* Architecture-specific PXE definitions */
-#include "errno.h" /* PXE status codes */
+#include <stdint.h>
+#include <errno.h> /* PXE status codes */
/** @addtogroup pxe Preboot eXecution Environment (PXE) API
* @{
diff --git a/gpxe/src/include/stddef.h b/gpxe/src/include/stddef.h
index 6f91d219..11ea9345 100644
--- a/gpxe/src/include/stddef.h
+++ b/gpxe/src/include/stddef.h
@@ -15,4 +15,10 @@
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
+/* __WCHAR_TYPE__ is defined by gcc and will change if -fshort-wchar is used */
+#ifndef __WCHAR_TYPE__
+#define __WCHAR_TYPE__ long int
+#endif
+typedef __WCHAR_TYPE__ wchar_t;
+
#endif /* STDDEF_H */
diff --git a/gpxe/src/include/stdlib.h b/gpxe/src/include/stdlib.h
index ae996962..f3dc7e41 100644
--- a/gpxe/src/include/stdlib.h
+++ b/gpxe/src/include/stdlib.h
@@ -68,5 +68,6 @@ static inline void srand ( unsigned int seed ) {
*/
extern int system ( const char *command );
+extern __cdecl int main ( void );
#endif /* STDLIB_H */
diff --git a/gpxe/src/include/unistd.h b/gpxe/src/include/unistd.h
index 7c44a0ce..dc1f67f6 100644
--- a/gpxe/src/include/unistd.h
+++ b/gpxe/src/include/unistd.h
@@ -4,7 +4,6 @@
#include <stddef.h>
#include <stdarg.h>
-unsigned int sleep ( unsigned int seconds );
extern int execv ( const char *command, char * const argv[] );
/**
@@ -22,10 +21,21 @@ extern int execv ( const char *command, char * const argv[] );
rc; \
} )
-void udelay(unsigned int usecs);
-void mdelay(unsigned int msecs);
+/* Pick up udelay() */
+#include <gpxe/timer.h>
-#define usleep(x) udelay(x)
+/*
+ * sleep() prototype is defined by POSIX.1. usleep() prototype is
+ * defined by 4.3BSD. udelay() and mdelay() prototypes are chosen to
+ * be reasonably sensible.
+ *
+ */
+
+extern unsigned int sleep ( unsigned int seconds );
+extern void mdelay ( unsigned long msecs );
+static inline __always_inline void usleep ( unsigned long usecs ) {
+ udelay ( usecs );
+}
#endif /* _UNISTD_H */
diff --git a/gpxe/src/include/usr/aoeboot.h b/gpxe/src/include/usr/aoeboot.h
deleted file mode 100644
index 0421ebcc..00000000
--- a/gpxe/src/include/usr/aoeboot.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _USR_AOEBOOT_H
-#define _USR_AOEBOOT_H
-
-extern int aoeboot ( const char *root_path );
-
-#endif /* _USR_AOEBOOT_H */
diff --git a/gpxe/src/include/usr/iscsiboot.h b/gpxe/src/include/usr/iscsiboot.h
deleted file mode 100644
index b17951d5..00000000
--- a/gpxe/src/include/usr/iscsiboot.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _USR_ISCSIBOOT_H
-#define _USR_ISCSIBOOT_H
-
-extern int iscsiboot ( const char *root_path );
-
-#endif /* _USR_ISCSIBOOT_H */
diff --git a/gpxe/src/interface/efi/efi_console.c b/gpxe/src/interface/efi/efi_console.c
new file mode 100644
index 00000000..b6e0dafd
--- /dev/null
+++ b/gpxe/src/interface/efi/efi_console.c
@@ -0,0 +1,273 @@
+/*
+ * Copyright (C) 2008 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 <stddef.h>
+#include <assert.h>
+#include <gpxe/efi/efi.h>
+#include <gpxe/ansiesc.h>
+#include <console.h>
+
+#define ATTR_BOLD 0x08
+
+#define ATTR_FCOL_MASK 0x07
+#define ATTR_FCOL_BLACK 0x00
+#define ATTR_FCOL_BLUE 0x01
+#define ATTR_FCOL_GREEN 0x02
+#define ATTR_FCOL_CYAN 0x03
+#define ATTR_FCOL_RED 0x04
+#define ATTR_FCOL_MAGENTA 0x05
+#define ATTR_FCOL_YELLOW 0x06
+#define ATTR_FCOL_WHITE 0x07
+
+#define ATTR_BCOL_MASK 0x70
+#define ATTR_BCOL_BLACK 0x00
+#define ATTR_BCOL_BLUE 0x10
+#define ATTR_BCOL_GREEN 0x20
+#define ATTR_BCOL_CYAN 0x30
+#define ATTR_BCOL_RED 0x40
+#define ATTR_BCOL_MAGENTA 0x50
+#define ATTR_BCOL_YELLOW 0x60
+#define ATTR_BCOL_WHITE 0x70
+
+#define ATTR_DEFAULT ATTR_FCOL_WHITE
+
+/** Current character attribute */
+static unsigned int efi_attr = ATTR_DEFAULT;
+
+/**
+ * Handle ANSI CUP (cursor position)
+ *
+ * @v count Parameter count
+ * @v params[0] Row (1 is top)
+ * @v params[1] Column (1 is left)
+ */
+static void efi_handle_cup ( unsigned int count __unused, int params[] ) {
+ EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *conout = efi_systab->ConOut;
+ int cx = ( params[1] - 1 );
+ int cy = ( params[0] - 1 );
+
+ if ( cx < 0 )
+ cx = 0;
+ if ( cy < 0 )
+ cy = 0;
+
+ conout->SetCursorPosition ( conout, cx, cy );
+}
+
+/**
+ * Handle ANSI ED (erase in page)
+ *
+ * @v count Parameter count
+ * @v params[0] Region to erase
+ */
+static void efi_handle_ed ( unsigned int count __unused,
+ int params[] __unused ) {
+ EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *conout = efi_systab->ConOut;
+
+ /* We assume that we always clear the whole screen */
+ assert ( params[0] == ANSIESC_ED_ALL );
+
+ conout->ClearScreen ( conout );
+}
+
+/**
+ * Handle ANSI SGR (set graphics rendition)
+ *
+ * @v count Parameter count
+ * @v params List of graphic rendition aspects
+ */
+static void efi_handle_sgr ( unsigned int count, int params[] ) {
+ EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *conout = efi_systab->ConOut;
+ static const uint8_t efi_attr_fcols[10] = {
+ ATTR_FCOL_BLACK, ATTR_FCOL_RED, ATTR_FCOL_GREEN,
+ ATTR_FCOL_YELLOW, ATTR_FCOL_BLUE, ATTR_FCOL_MAGENTA,
+ ATTR_FCOL_CYAN, ATTR_FCOL_WHITE,
+ ATTR_FCOL_WHITE, ATTR_FCOL_WHITE /* defaults */
+ };
+ static const uint8_t efi_attr_bcols[10] = {
+ ATTR_BCOL_BLACK, ATTR_BCOL_RED, ATTR_BCOL_GREEN,
+ ATTR_BCOL_YELLOW, ATTR_BCOL_BLUE, ATTR_BCOL_MAGENTA,
+ ATTR_BCOL_CYAN, ATTR_BCOL_WHITE,
+ ATTR_BCOL_BLACK, ATTR_BCOL_BLACK /* defaults */
+ };
+ unsigned int i;
+ int aspect;
+
+ for ( i = 0 ; i < count ; i++ ) {
+ aspect = params[i];
+ if ( aspect == 0 ) {
+ efi_attr = ATTR_DEFAULT;
+ } else if ( aspect == 1 ) {
+ efi_attr |= ATTR_BOLD;
+ } else if ( aspect == 22 ) {
+ efi_attr &= ~ATTR_BOLD;
+ } else if ( ( aspect >= 30 ) && ( aspect <= 39 ) ) {
+ efi_attr &= ~ATTR_FCOL_MASK;
+ efi_attr |= efi_attr_fcols[ aspect - 30 ];
+ } else if ( ( aspect >= 40 ) && ( aspect <= 49 ) ) {
+ efi_attr &= ~ATTR_BCOL_MASK;
+ efi_attr |= efi_attr_bcols[ aspect - 40 ];
+ }
+ }
+
+ conout->SetAttribute ( conout, efi_attr );
+}
+
+/** EFI console ANSI escape sequence handlers */
+static struct ansiesc_handler efi_ansiesc_handlers[] = {
+ { ANSIESC_CUP, efi_handle_cup },
+ { ANSIESC_ED, efi_handle_ed },
+ { ANSIESC_SGR, efi_handle_sgr },
+ { 0, NULL }
+};
+
+/** EFI console ANSI escape sequence context */
+static struct ansiesc_context efi_ansiesc_ctx = {
+ .handlers = efi_ansiesc_handlers,
+};
+
+/**
+ * Print a character to EFI console
+ *
+ * @v character Character to be printed
+ */
+static void efi_putchar ( int character ) {
+ EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *conout = efi_systab->ConOut;
+ wchar_t wstr[] = { character, 0 };
+
+ /* Intercept ANSI escape sequences */
+ character = ansiesc_process ( &efi_ansiesc_ctx, character );
+ if ( character < 0 )
+ return;
+
+ conout->OutputString ( conout, wstr );
+}
+
+/**
+ * Pointer to current ANSI output sequence
+ *
+ * While we are in the middle of returning an ANSI sequence for a
+ * special key, this will point to the next character to return. When
+ * not in the middle of such a sequence, this will point to a NUL
+ * (note: not "will be NULL").
+ */
+static const char *ansi_input = "";
+
+/** Mapping from EFI scan codes to ANSI escape sequences */
+static const char *ansi_sequences[] = {
+ [SCAN_UP] = "[A",
+ [SCAN_DOWN] = "[B",
+ [SCAN_RIGHT] = "[C",
+ [SCAN_LEFT] = "[D",
+ [SCAN_HOME] = "[H",
+ [SCAN_END] = "[F",
+ [SCAN_INSERT] = "[2~",
+ /* EFI translates an incoming backspace via the serial console
+ * into a SCAN_DELETE. There's not much we can do about this.
+ */
+ [SCAN_DELETE] = "[3~",
+ [SCAN_PAGE_UP] = "[5~",
+ [SCAN_PAGE_DOWN] = "[6~",
+ /* EFI translates some (but not all) incoming escape sequences
+ * via the serial console into equivalent scancodes. When it
+ * doesn't recognise a sequence, it helpfully(!) translates
+ * the initial ESC and passes the remainder through verbatim.
+ * Treating SCAN_ESC as equivalent to an empty escape sequence
+ * works around this bug.
+ */
+ [SCAN_ESC] = "",
+};
+
+/**
+ * Get ANSI escape sequence corresponding to EFI scancode
+ *
+ * @v scancode EFI scancode
+ * @ret ansi_seq ANSI escape sequence, if any, otherwise NULL
+ */
+static const char * scancode_to_ansi_seq ( unsigned int scancode ) {
+ if ( scancode < ( sizeof ( ansi_sequences ) /
+ sizeof ( ansi_sequences[0] ) ) ) {
+ return ansi_sequences[scancode];
+ }
+ return NULL;
+}
+
+/**
+ * Get character from EFI console
+ *
+ * @ret character Character read from console
+ */
+static int efi_getchar ( void ) {
+ EFI_SIMPLE_TEXT_INPUT_PROTOCOL *conin = efi_systab->ConIn;
+ const char *ansi_seq;
+ EFI_INPUT_KEY key;
+ EFI_STATUS efirc;
+
+ /* If we are mid-sequence, pass out the next byte */
+ if ( *ansi_input )
+ return *(ansi_input++);
+
+ /* Read key from real EFI console */
+ if ( ( efirc = conin->ReadKeyStroke ( conin, &key ) ) != 0 ) {
+ DBG ( "EFI could not read keystroke: %lx\n", efirc );
+ return 0;
+ }
+ DBG2 ( "EFI read key stroke with unicode %04x scancode %04x\n",
+ key.UnicodeChar, key.ScanCode );
+
+ /* If key has a Unicode representation, return it */
+ if ( key.UnicodeChar )
+ return key.UnicodeChar;
+
+ /* Otherwise, check for a special key that we know about */
+ if ( ( ansi_seq = scancode_to_ansi_seq ( key.ScanCode ) ) ) {
+ /* Start of escape sequence: return ESC (0x1b) */
+ ansi_input = ansi_seq;
+ return 0x1b;
+ }
+
+ return 0;
+}
+
+/**
+ * Check for character ready to read from EFI console
+ *
+ * @ret True Character available to read
+ * @ret False No character available to read
+ */
+static int efi_iskey ( void ) {
+ EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+ EFI_SIMPLE_TEXT_INPUT_PROTOCOL *conin = efi_systab->ConIn;
+ EFI_STATUS efirc;
+
+ /* If we are mid-sequence, we are always ready */
+ if ( *ansi_input )
+ return 1;
+
+ /* Check to see if the WaitForKey event has fired */
+ if ( ( efirc = bs->CheckEvent ( conin->WaitForKey ) ) == 0 )
+ return 1;
+
+ return 0;
+}
+
+struct console_driver efi_console __console_driver = {
+ .putchar = efi_putchar,
+ .getchar = efi_getchar,
+ .iskey = efi_iskey,
+};
diff --git a/gpxe/src/interface/efi/efi_entry.c b/gpxe/src/interface/efi/efi_entry.c
new file mode 100644
index 00000000..b00828ad
--- /dev/null
+++ b/gpxe/src/interface/efi/efi_entry.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2008 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 <stdlib.h>
+#include <gpxe/efi/efi.h>
+#include <gpxe/uuid.h>
+
+/** Image handle passed to entry point */
+EFI_HANDLE efi_image_handle;
+
+/** System table passed to entry point */
+EFI_SYSTEM_TABLE *efi_systab;
+
+/** Declared used EFI protocols */
+static struct efi_protocol efi_protocols[0] \
+ __table_start ( struct efi_protocol, efi_protocols );
+static struct efi_protocol efi_protocols_end[0] \
+ __table_end ( struct efi_protocol, efi_protocols );
+
+/**
+ * EFI entry point
+ *
+ * @v image_handle Image handle
+ * @v systab System table
+ * @ret efirc EFI return status code
+ */
+EFI_STATUS EFIAPI efi_entry ( EFI_HANDLE image_handle,
+ EFI_SYSTEM_TABLE *systab ) {
+ EFI_BOOT_SERVICES *bs;
+ struct efi_protocol *prot;
+ EFI_STATUS efirc;
+
+ /* Store image handle and system table pointer for future use */
+ efi_image_handle = image_handle;
+ efi_systab = systab;
+
+ /* Sanity checks */
+ if ( ! systab )
+ return EFI_NOT_AVAILABLE_YET;
+ if ( ! systab->ConOut )
+ return EFI_NOT_AVAILABLE_YET;
+ if ( ! systab->BootServices ) {
+ DBGC ( systab, "EFI provided no BootServices entry point\n" );
+ return EFI_NOT_AVAILABLE_YET;
+ }
+ if ( ! systab->RuntimeServices ) {
+ DBGC ( systab, "EFI provided no RuntimeServices entry "
+ "point\n" );
+ return EFI_NOT_AVAILABLE_YET;
+ }
+ DBGC ( systab, "EFI handle %p systab %p\n", image_handle, systab );
+
+ /* Look up required protocols */
+ bs = systab->BootServices;
+ for ( prot = efi_protocols ; prot < efi_protocols_end ; prot++ ) {
+ if ( ( efirc = bs->LocateProtocol ( &prot->u.guid, NULL,
+ prot->protocol ) ) != 0 ) {
+ DBGC ( systab, "EFI does not provide protocol %s\n",
+ uuid_ntoa ( &prot->u.uuid ) );
+ return efirc;
+ }
+ DBGC ( systab, "EFI protocol %s is at %p\n",
+ uuid_ntoa ( &prot->u.uuid ), *(prot->protocol) );
+ }
+
+ /* Call to main() */
+ return RC_TO_EFIRC ( main () );
+}
diff --git a/gpxe/src/interface/efi/efi_io.c b/gpxe/src/interface/efi/efi_io.c
new file mode 100644
index 00000000..1d4537ab
--- /dev/null
+++ b/gpxe/src/interface/efi/efi_io.c
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2008 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 <assert.h>
+#include <gpxe/io.h>
+#include <gpxe/efi/efi.h>
+#include <gpxe/efi/Protocol/CpuIo.h>
+#include <gpxe/efi/efi_io.h>
+
+/** @file
+ *
+ * gPXE I/O API for EFI
+ *
+ */
+
+/** CPU I/O protocol */
+static EFI_CPU_IO_PROTOCOL *cpu_io;
+EFI_REQUIRE_PROTOCOL ( EFI_CPU_IO_PROTOCOL, &cpu_io );
+
+/** Maximum address that can be used for port I/O */
+#define MAX_PORT_ADDRESS 0xffff
+
+/**
+ * Determine whether or not address is a port I/O address
+ *
+ * @v io_addr I/O address
+ * @v is_port I/O address is a port I/O address
+ */
+#define IS_PORT_ADDRESS(io_addr) \
+ ( ( ( intptr_t ) (io_addr) ) <= MAX_PORT_ADDRESS )
+
+/**
+ * Determine EFI CPU I/O width code
+ *
+ * @v size Size of value
+ * @ret width EFI width code
+ *
+ * Someone at Intel clearly gets paid by the number of lines of code
+ * they write. No-one should ever be able to make I/O this
+ * convoluted. The EFI_CPU_IO_PROTOCOL_WIDTH enum is my favourite
+ * idiocy.
+ */
+static EFI_CPU_IO_PROTOCOL_WIDTH efi_width ( size_t size ) {
+ switch ( size ) {
+ case 1 : return EfiCpuIoWidthFifoUint8;
+ case 2 : return EfiCpuIoWidthFifoUint16;
+ case 4 : return EfiCpuIoWidthFifoUint32;
+ case 8 : return EfiCpuIoWidthFifoUint64;
+ default :
+ assert ( 0 );
+ /* I wonder what this will actually do... */
+ return EfiCpuIoWidthMaximum;
+ }
+}
+
+/**
+ * Read from device
+ *
+ * @v io_addr I/O address
+ * @v size Size of value
+ * @ret data Value read
+ */
+unsigned long long efi_ioread ( volatile void *io_addr, size_t size ) {
+ EFI_CPU_IO_PROTOCOL_IO_MEM read;
+ unsigned long long data = 0;
+ EFI_STATUS efirc;
+
+ read = ( IS_PORT_ADDRESS ( io_addr ) ?
+ cpu_io->Io.Read : cpu_io->Mem.Read );
+
+ if ( ( efirc = read ( cpu_io, efi_width ( size ),
+ ( intptr_t ) io_addr, 1,
+ ( void * ) &data ) ) != 0 ) {
+ DBG ( "EFI I/O read at %p failed: %lx\n", io_addr, efirc );
+ return -1ULL;
+ }
+
+ return data;
+}
+
+/**
+ * Write to device
+ *
+ * @v data Value to write
+ * @v io_addr I/O address
+ * @v size Size of value
+ */
+void efi_iowrite ( unsigned long long data, volatile void *io_addr,
+ size_t size ) {
+ EFI_CPU_IO_PROTOCOL_IO_MEM write;
+ EFI_STATUS efirc;
+
+ write = ( IS_PORT_ADDRESS ( io_addr ) ?
+ cpu_io->Io.Write : cpu_io->Mem.Write );
+
+ if ( ( efirc = write ( cpu_io, efi_width ( size ),
+ ( intptr_t ) io_addr, 1,
+ ( void * ) &data ) ) != 0 ) {
+ DBG ( "EFI I/O write at %p failed: %lx\n", io_addr, efirc );
+ }
+}
+
+/**
+ * String read from device
+ *
+ * @v io_addr I/O address
+ * @v data Data buffer
+ * @v size Size of values
+ * @v count Number of values to read
+ */
+void efi_ioreads ( volatile void *io_addr, void *data,
+ size_t size, unsigned int count ) {
+ EFI_CPU_IO_PROTOCOL_IO_MEM read;
+ EFI_STATUS efirc;
+
+ read = ( IS_PORT_ADDRESS ( io_addr ) ?
+ cpu_io->Io.Read : cpu_io->Mem.Read );
+
+ if ( ( efirc = read ( cpu_io, efi_width ( size ),
+ ( intptr_t ) io_addr, count,
+ ( void * ) data ) ) != 0 ) {
+ DBG ( "EFI I/O string read at %p failed: %lx\n",
+ io_addr, efirc );
+ }
+}
+
+/**
+ * String write to device
+ *
+ * @v io_addr I/O address
+ * @v data Data buffer
+ * @v size Size of values
+ * @v count Number of values to write
+ */
+void efi_iowrites ( volatile void *io_addr, const void *data,
+ size_t size, unsigned int count ) {
+ EFI_CPU_IO_PROTOCOL_IO_MEM write;
+ EFI_STATUS efirc;
+
+ write = ( IS_PORT_ADDRESS ( io_addr ) ?
+ cpu_io->Io.Write : cpu_io->Mem.Write );
+
+ if ( ( efirc = write ( cpu_io, efi_width ( size ),
+ ( intptr_t ) io_addr, count,
+ ( void * ) data ) ) != 0 ) {
+ DBG ( "EFI I/O write at %p failed: %lx\n",
+ io_addr, efirc );
+ }
+}
+
+/**
+ * Wait for I/O-mapped operation to complete
+ *
+ */
+static void efi_iodelay ( void ) {
+ /* Write to non-existent port. Probably x86-only. */
+ outb ( 0, 0x80 );
+}
+
+PROVIDE_IOAPI_INLINE ( efi, phys_to_bus );
+PROVIDE_IOAPI_INLINE ( efi, bus_to_phys );
+PROVIDE_IOAPI_INLINE ( efi, ioremap );
+PROVIDE_IOAPI_INLINE ( efi, iounmap );
+PROVIDE_IOAPI_INLINE ( efi, io_to_bus );
+PROVIDE_IOAPI_INLINE ( efi, readb );
+PROVIDE_IOAPI_INLINE ( efi, readw );
+PROVIDE_IOAPI_INLINE ( efi, readl );
+PROVIDE_IOAPI_INLINE ( efi, readq );
+PROVIDE_IOAPI_INLINE ( efi, writeb );
+PROVIDE_IOAPI_INLINE ( efi, writew );
+PROVIDE_IOAPI_INLINE ( efi, writel );
+PROVIDE_IOAPI_INLINE ( efi, writeq );
+PROVIDE_IOAPI_INLINE ( efi, inb );
+PROVIDE_IOAPI_INLINE ( efi, inw );
+PROVIDE_IOAPI_INLINE ( efi, inl );
+PROVIDE_IOAPI_INLINE ( efi, outb );
+PROVIDE_IOAPI_INLINE ( efi, outw );
+PROVIDE_IOAPI_INLINE ( efi, outl );
+PROVIDE_IOAPI_INLINE ( efi, insb );
+PROVIDE_IOAPI_INLINE ( efi, insw );
+PROVIDE_IOAPI_INLINE ( efi, insl );
+PROVIDE_IOAPI_INLINE ( efi, outsb );
+PROVIDE_IOAPI_INLINE ( efi, outsw );
+PROVIDE_IOAPI_INLINE ( efi, outsl );
+PROVIDE_IOAPI ( efi, iodelay, efi_iodelay );
+PROVIDE_IOAPI_INLINE ( efi, mb );
diff --git a/gpxe/src/interface/efi/efi_pci.c b/gpxe/src/interface/efi/efi_pci.c
new file mode 100644
index 00000000..93408165
--- /dev/null
+++ b/gpxe/src/interface/efi/efi_pci.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2008 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 <errno.h>
+#include <gpxe/pci.h>
+#include <gpxe/efi/efi.h>
+#include <gpxe/efi/Protocol/PciRootBridgeIo.h>
+
+/** @file
+ *
+ * gPXE PCI I/O API for EFI
+ *
+ */
+
+/** PCI root bridge I/O protocol */
+static EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *efipci;
+EFI_REQUIRE_PROTOCOL ( EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL, &efipci );
+
+static unsigned long efipci_address ( struct pci_device *pci,
+ unsigned long location ) {
+ return EFI_PCI_ADDRESS ( pci->bus, PCI_SLOT ( pci->devfn ),
+ PCI_FUNC ( pci->devfn ),
+ EFIPCI_OFFSET ( location ) );
+}
+
+int efipci_read ( struct pci_device *pci, unsigned long location,
+ void *value ) {
+ EFI_STATUS efirc;
+
+ if ( ( efirc = efipci->Pci.Read ( efipci, EFIPCI_WIDTH ( location ),
+ efipci_address ( pci, location ), 1,
+ value ) ) != 0 ) {
+ DBG ( "EFIPCI config read from %02x:%02x.%x offset %02lx "
+ "failed: %lx\n", pci->bus, PCI_SLOT ( pci->devfn ),
+ PCI_FUNC ( pci->devfn ), EFIPCI_OFFSET ( location ),
+ efirc );
+ return -EIO;
+ }
+
+ return 0;
+}
+
+int efipci_write ( struct pci_device *pci, unsigned long location,
+ unsigned long value ) {
+ EFI_STATUS efirc;
+
+ if ( ( efirc = efipci->Pci.Write ( efipci, EFIPCI_WIDTH ( location ),
+ efipci_address ( pci, location ), 1,
+ &value ) ) != 0 ) {
+ DBG ( "EFIPCI config write to %02x:%02x.%x offset %02lx "
+ "failed: %lx\n", pci->bus, PCI_SLOT ( pci->devfn ),
+ PCI_FUNC ( pci->devfn ), EFIPCI_OFFSET ( location ),
+ efirc );
+ return -EIO;
+ }
+
+ return 0;
+}
+
+PROVIDE_PCIAPI_INLINE ( efi, pci_max_bus );
+PROVIDE_PCIAPI_INLINE ( efi, pci_read_config_byte );
+PROVIDE_PCIAPI_INLINE ( efi, pci_read_config_word );
+PROVIDE_PCIAPI_INLINE ( efi, pci_read_config_dword );
+PROVIDE_PCIAPI_INLINE ( efi, pci_write_config_byte );
+PROVIDE_PCIAPI_INLINE ( efi, pci_write_config_word );
+PROVIDE_PCIAPI_INLINE ( efi, pci_write_config_dword );
diff --git a/gpxe/src/interface/efi/efi_snp.c b/gpxe/src/interface/efi/efi_snp.c
new file mode 100644
index 00000000..40136623
--- /dev/null
+++ b/gpxe/src/interface/efi/efi_snp.c
@@ -0,0 +1,980 @@
+/*
+ * Copyright (C) 2008 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 <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <byteswap.h>
+#include <gpxe/netdevice.h>
+#include <gpxe/iobuf.h>
+#include <gpxe/in.h>
+#include <gpxe/pci.h>
+#include <gpxe/efi/efi.h>
+#include <gpxe/efi/Protocol/DriverBinding.h>
+#include <gpxe/efi/Protocol/PciIo.h>
+#include <gpxe/efi/Protocol/SimpleNetwork.h>
+
+/** @file
+ *
+ * gPXE EFI SNP interface
+ *
+ */
+
+/** An SNP device */
+struct efi_snp_device {
+ /** The underlying gPXE network device */
+ struct net_device *netdev;
+ /** The SNP structure itself */
+ EFI_SIMPLE_NETWORK_PROTOCOL snp;
+ /** The SNP "mode" (parameters) */
+ EFI_SIMPLE_NETWORK_MODE mode;
+ /** Outstanding TX packet count (via "interrupt status")
+ *
+ * Used in order to generate TX completions.
+ */
+ unsigned int tx_count_interrupts;
+ /** Outstanding TX packet count (via "recycled tx buffers")
+ *
+ * Used in order to generate TX completions.
+ */
+ unsigned int tx_count_txbufs;
+ /** Outstanding RX packet count (via "interrupt status") */
+ unsigned int rx_count_interrupts;
+ /** Outstanding RX packet count (via WaitForPacket event) */
+ unsigned int rx_count_events;
+};
+
+/** EFI simple network protocol GUID */
+static EFI_GUID efi_simple_network_protocol_guid
+ = EFI_SIMPLE_NETWORK_PROTOCOL_GUID;
+
+/** EFI driver binding protocol GUID */
+static EFI_GUID efi_driver_binding_protocol_guid
+ = EFI_DRIVER_BINDING_PROTOCOL_GUID;
+
+/** EFI PCI I/O protocol GUID */
+static EFI_GUID efi_pci_io_protocol_guid
+ = EFI_PCI_IO_PROTOCOL_GUID;
+
+/**
+ * Set EFI SNP mode based on gPXE net device parameters
+ *
+ * @v snp SNP interface
+ */
+static void efi_snp_set_mode ( struct efi_snp_device *snpdev ) {
+ struct net_device *netdev = snpdev->netdev;
+ EFI_SIMPLE_NETWORK_MODE *mode = &snpdev->mode;
+ unsigned int ll_addr_len = netdev->ll_protocol->ll_addr_len;
+
+ mode->HwAddressSize = ll_addr_len;
+ mode->MediaHeaderSize = netdev->ll_protocol->ll_header_len;
+ mode->MaxPacketSize = netdev->max_pkt_len;
+ mode->ReceiveFilterMask = ( EFI_SIMPLE_NETWORK_RECEIVE_UNICAST |
+ EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST |
+ EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST );
+ assert ( ll_addr_len <= sizeof ( mode->CurrentAddress ) );
+ memcpy ( &mode->CurrentAddress, netdev->ll_addr, ll_addr_len );
+ memcpy ( &mode->BroadcastAddress, netdev->ll_protocol->ll_broadcast,
+ ll_addr_len );
+ memcpy ( &mode->PermanentAddress, netdev->ll_addr, ll_addr_len );
+ mode->IfType = ntohs ( netdev->ll_protocol->ll_proto );
+ mode->MacAddressChangeable = TRUE;
+ mode->MediaPresentSupported = TRUE;
+ mode->MediaPresent = ( netdev_link_ok ( netdev ) ? TRUE : FALSE );
+}
+
+/**
+ * Poll net device and count received packets
+ *
+ * @v snpdev SNP device
+ */
+static void efi_snp_poll ( struct efi_snp_device *snpdev ) {
+ struct io_buffer *iobuf;
+ unsigned int before = 0;
+ unsigned int after = 0;
+ unsigned int arrived;
+
+ /* We have to report packet arrivals, and this is the easiest
+ * way to fake it.
+ */
+ list_for_each_entry ( iobuf, &snpdev->netdev->rx_queue, list )
+ before++;
+ netdev_poll ( snpdev->netdev );
+ list_for_each_entry ( iobuf, &snpdev->netdev->rx_queue, list )
+ after++;
+ arrived = ( after - before );
+
+ snpdev->rx_count_interrupts += arrived;
+ snpdev->rx_count_events += arrived;
+}
+
+/**
+ * Change SNP state from "stopped" to "started"
+ *
+ * @v snp SNP interface
+ * @ret efirc EFI status code
+ */
+static EFI_STATUS EFIAPI
+efi_snp_start ( EFI_SIMPLE_NETWORK_PROTOCOL *snp ) {
+ struct efi_snp_device *snpdev =
+ container_of ( snp, struct efi_snp_device, snp );
+
+ DBGC2 ( snpdev, "SNPDEV %p START\n", snpdev );
+
+ snpdev->mode.State = EfiSimpleNetworkStarted;
+ return 0;
+}
+
+/**
+ * Change SNP state from "started" to "stopped"
+ *
+ * @v snp SNP interface
+ * @ret efirc EFI status code
+ */
+static EFI_STATUS EFIAPI
+efi_snp_stop ( EFI_SIMPLE_NETWORK_PROTOCOL *snp ) {
+ struct efi_snp_device *snpdev =
+ container_of ( snp, struct efi_snp_device, snp );
+
+ DBGC2 ( snpdev, "SNPDEV %p STOP\n", snpdev );
+
+ snpdev->mode.State = EfiSimpleNetworkStopped;
+ return 0;
+}
+
+/**
+ * Open the network device
+ *
+ * @v snp SNP interface
+ * @v extra_rx_bufsize Extra RX buffer size, in bytes
+ * @v extra_tx_bufsize Extra TX buffer size, in bytes
+ * @ret efirc EFI status code
+ */
+static EFI_STATUS EFIAPI
+efi_snp_initialize ( EFI_SIMPLE_NETWORK_PROTOCOL *snp,
+ UINTN extra_rx_bufsize, UINTN extra_tx_bufsize ) {
+ struct efi_snp_device *snpdev =
+ container_of ( snp, struct efi_snp_device, snp );
+ int rc;
+
+ DBGC2 ( snpdev, "SNPDEV %p INITIALIZE (%ld extra RX, %ld extra TX)\n",
+ snpdev, extra_rx_bufsize, extra_tx_bufsize );
+
+ if ( ( rc = netdev_open ( snpdev->netdev ) ) != 0 ) {
+ DBGC ( snpdev, "SNPDEV %p could not open %s: %s\n",
+ snpdev, snpdev->netdev->name, strerror ( rc ) );
+ return RC_TO_EFIRC ( rc );
+ }
+
+ snpdev->mode.State = EfiSimpleNetworkInitialized;
+ return 0;
+}
+
+/**
+ * Reset the network device
+ *
+ * @v snp SNP interface
+ * @v ext_verify Extended verification required
+ * @ret efirc EFI status code
+ */
+static EFI_STATUS EFIAPI
+efi_snp_reset ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN ext_verify ) {
+ struct efi_snp_device *snpdev =
+ container_of ( snp, struct efi_snp_device, snp );
+ int rc;
+
+ DBGC2 ( snpdev, "SNPDEV %p RESET (%s extended verification)\n",
+ snpdev, ( ext_verify ? "with" : "without" ) );
+
+ netdev_close ( snpdev->netdev );
+ snpdev->mode.State = EfiSimpleNetworkStarted;
+
+ if ( ( rc = netdev_open ( snpdev->netdev ) ) != 0 ) {
+ DBGC ( snpdev, "SNPDEV %p could not reopen %s: %s\n",
+ snpdev, snpdev->netdev->name, strerror ( rc ) );
+ return RC_TO_EFIRC ( rc );
+ }
+
+ snpdev->mode.State = EfiSimpleNetworkInitialized;
+ return 0;
+}
+
+/**
+ * Shut down the network device
+ *
+ * @v snp SNP interface
+ * @ret efirc EFI status code
+ */
+static EFI_STATUS EFIAPI
+efi_snp_shutdown ( EFI_SIMPLE_NETWORK_PROTOCOL *snp ) {
+ struct efi_snp_device *snpdev =
+ container_of ( snp, struct efi_snp_device, snp );
+
+ DBGC2 ( snpdev, "SNPDEV %p SHUTDOWN\n", snpdev );
+
+ netdev_close ( snpdev->netdev );
+ snpdev->mode.State = EfiSimpleNetworkStarted;
+ return 0;
+}
+
+/**
+ * Manage receive filters
+ *
+ * @v snp SNP interface
+ * @v enable Receive filters to enable
+ * @v disable Receive filters to disable
+ * @v mcast_reset Reset multicast filters
+ * @v mcast_count Number of multicast filters
+ * @v mcast Multicast filters
+ * @ret efirc EFI status code
+ */
+static EFI_STATUS EFIAPI
+efi_snp_receive_filters ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, UINT32 enable,
+ UINT32 disable, BOOLEAN mcast_reset,
+ UINTN mcast_count, EFI_MAC_ADDRESS *mcast ) {
+ struct efi_snp_device *snpdev =
+ container_of ( snp, struct efi_snp_device, snp );
+ unsigned int i;
+
+ DBGC2 ( snpdev, "SNPDEV %p RECEIVE_FILTERS %08lx&~%08lx%s %ld mcast\n",
+ snpdev, enable, disable, ( mcast_reset ? " reset" : "" ),
+ mcast_count );
+ for ( i = 0 ; i < mcast_count ; i++ ) {
+ DBGC2_HDA ( snpdev, i, &mcast[i],
+ snpdev->netdev->ll_protocol->ll_addr_len );
+ }
+
+ /* Lie through our teeth, otherwise MNP refuses to accept us */
+ return 0;
+}
+
+/**
+ * Set station address
+ *
+ * @v snp SNP interface
+ * @v reset Reset to permanent address
+ * @v new New station address
+ * @ret efirc EFI status code
+ */
+static EFI_STATUS EFIAPI
+efi_snp_station_address ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN reset,
+ EFI_MAC_ADDRESS *new ) {
+ struct efi_snp_device *snpdev =
+ container_of ( snp, struct efi_snp_device, snp );
+ struct ll_protocol *ll_protocol = snpdev->netdev->ll_protocol;
+
+ DBGC2 ( snpdev, "SNPDEV %p STATION_ADDRESS %s\n", snpdev,
+ ( reset ? "reset" : ll_protocol->ntoa ( new ) ) );
+
+ /* Set the MAC address */
+ if ( reset )
+ new = &snpdev->mode.PermanentAddress;
+ memcpy ( snpdev->netdev->ll_addr, new, ll_protocol->ll_addr_len );
+
+ /* MAC address changes take effect only on netdev_open() */
+ if ( snpdev->netdev->state & NETDEV_OPEN ) {
+ DBGC ( snpdev, "SNPDEV %p MAC address changed while net "
+ "devive open\n", snpdev );
+ }
+
+ return 0;
+}
+
+/**
+ * Get (or reset) statistics
+ *
+ * @v snp SNP interface
+ * @v reset Reset statistics
+ * @v stats_len Size of statistics table
+ * @v stats Statistics table
+ * @ret efirc EFI status code
+ */
+static EFI_STATUS EFIAPI
+efi_snp_statistics ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN reset,
+ UINTN *stats_len, EFI_NETWORK_STATISTICS *stats ) {
+ struct efi_snp_device *snpdev =
+ container_of ( snp, struct efi_snp_device, snp );
+ EFI_NETWORK_STATISTICS stats_buf;
+
+ DBGC2 ( snpdev, "SNPDEV %p STATISTICS%s", snpdev,
+ ( reset ? " reset" : "" ) );
+
+ /* Gather statistics */
+ memset ( &stats_buf, 0, sizeof ( stats_buf ) );
+ stats_buf.TxGoodFrames = snpdev->netdev->tx_stats.good;
+ stats_buf.TxDroppedFrames = snpdev->netdev->tx_stats.bad;
+ stats_buf.TxTotalFrames = ( snpdev->netdev->tx_stats.good +
+ snpdev->netdev->tx_stats.bad );
+ stats_buf.RxGoodFrames = snpdev->netdev->rx_stats.good;
+ stats_buf.RxDroppedFrames = snpdev->netdev->rx_stats.bad;
+ stats_buf.RxTotalFrames = ( snpdev->netdev->rx_stats.good +
+ snpdev->netdev->rx_stats.bad );
+ if ( *stats_len > sizeof ( stats_buf ) )
+ *stats_len = sizeof ( stats_buf );
+ if ( stats )
+ memcpy ( stats, &stats_buf, *stats_len );
+
+ /* Reset statistics if requested to do so */
+ if ( reset ) {
+ memset ( &snpdev->netdev->tx_stats, 0,
+ sizeof ( snpdev->netdev->tx_stats ) );
+ memset ( &snpdev->netdev->rx_stats, 0,
+ sizeof ( snpdev->netdev->rx_stats ) );
+ }
+
+ return 0;
+}
+
+/**
+ * Convert multicast IP address to MAC address
+ *
+ * @v snp SNP interface
+ * @v ipv6 Address is IPv6
+ * @v ip IP address
+ * @v mac MAC address
+ * @ret efirc EFI status code
+ */
+static EFI_STATUS EFIAPI
+efi_snp_mcast_ip_to_mac ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN ipv6,
+ EFI_IP_ADDRESS *ip, EFI_MAC_ADDRESS *mac ) {
+ struct efi_snp_device *snpdev =
+ container_of ( snp, struct efi_snp_device, snp );
+ struct ll_protocol *ll_protocol = snpdev->netdev->ll_protocol;
+ const char *ip_str;
+ int rc;
+
+ ip_str = ( ipv6 ? "(IPv6)" /* FIXME when we have inet6_ntoa() */ :
+ inet_ntoa ( *( ( struct in_addr * ) ip ) ) );
+ DBGC2 ( snpdev, "SNPDEV %p MCAST_IP_TO_MAC %s\n", snpdev, ip_str );
+
+ /* Try to hash the address */
+ if ( ( rc = ll_protocol->mc_hash ( ( ipv6 ? AF_INET6 : AF_INET ),
+ ip, mac ) ) != 0 ) {
+ DBGC ( snpdev, "SNPDEV %p could not hash %s: %s\n",
+ snpdev, ip_str, strerror ( rc ) );
+ return RC_TO_EFIRC ( rc );
+ }
+
+ return 0;
+}
+
+/**
+ * Read or write non-volatile storage
+ *
+ * @v snp SNP interface
+ * @v read Operation is a read
+ * @v offset Starting offset within NVRAM
+ * @v len Length of data buffer
+ * @v data Data buffer
+ * @ret efirc EFI status code
+ */
+static EFI_STATUS EFIAPI
+efi_snp_nvdata ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN read,
+ UINTN offset, UINTN len, VOID *data ) {
+ struct efi_snp_device *snpdev =
+ container_of ( snp, struct efi_snp_device, snp );
+
+ DBGC2 ( snpdev, "SNPDEV %p NVDATA %s %lx+%lx\n", snpdev,
+ ( read ? "read" : "write" ), offset, len );
+ if ( ! read )
+ DBGC2_HDA ( snpdev, offset, data, len );
+
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ * Read interrupt status and TX recycled buffer status
+ *
+ * @v snp SNP interface
+ * @v interrupts Interrupt status, or NULL
+ * @v txbufs Recycled transmit buffer address, or NULL
+ * @ret efirc EFI status code
+ */
+static EFI_STATUS EFIAPI
+efi_snp_get_status ( EFI_SIMPLE_NETWORK_PROTOCOL *snp,
+ UINT32 *interrupts, VOID **txbufs ) {
+ struct efi_snp_device *snpdev =
+ container_of ( snp, struct efi_snp_device, snp );
+
+ DBGC2 ( snpdev, "SNPDEV %p GET_STATUS", snpdev );
+
+ /* Poll the network device */
+ efi_snp_poll ( snpdev );
+
+ /* Interrupt status. In practice, this seems to be used only
+ * to detect TX completions.
+ */
+ if ( interrupts ) {
+ *interrupts = 0;
+ /* Report TX completions once queue is empty; this
+ * avoids having to add hooks in the net device layer.
+ */
+ if ( snpdev->tx_count_interrupts &&
+ list_empty ( &snpdev->netdev->tx_queue ) ) {
+ *interrupts |= EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT;
+ snpdev->tx_count_interrupts--;
+ }
+ /* Report RX */
+ if ( snpdev->rx_count_interrupts ) {
+ *interrupts |= EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT;
+ snpdev->rx_count_interrupts--;
+ }
+ DBGC2 ( snpdev, " INTS:%02lx", *interrupts );
+ }
+
+ /* TX completions. It would be possible to design a more
+ * idiotic scheme for this, but it would be a challenge.
+ * According to the UEFI header file, txbufs will be filled in
+ * with a list of "recycled transmit buffers" (i.e. completed
+ * TX buffers). Observant readers may care to note that
+ * *txbufs is a void pointer. Precisely how a list of
+ * completed transmit buffers is meant to be represented as an
+ * array of voids is left as an exercise for the reader.
+ *
+ * The only users of this interface (MnpDxe/MnpIo.c and
+ * PxeBcDxe/Bc.c within the EFI dev kit) both just poll until
+ * seeing a non-NULL result return in txbufs. This is valid
+ * provided that they do not ever attempt to transmit more
+ * than one packet concurrently (and that TX never times out).
+ */
+ if ( txbufs ) {
+ if ( snpdev->tx_count_txbufs &&
+ list_empty ( &snpdev->netdev->tx_queue ) ) {
+ *txbufs = "Which idiot designed this API?";
+ snpdev->tx_count_txbufs--;
+ } else {
+ *txbufs = NULL;
+ }
+ DBGC2 ( snpdev, " TX:%s", ( *txbufs ? "some" : "none" ) );
+ }
+
+ DBGC2 ( snpdev, "\n" );
+ return 0;
+}
+
+/**
+ * Start packet transmission
+ *
+ * @v snp SNP interface
+ * @v ll_header_len Link-layer header length, if to be filled in
+ * @v len Length of data buffer
+ * @v data Data buffer
+ * @v ll_src Link-layer source address, if specified
+ * @v ll_dest Link-layer destination address, if specified
+ * @v net_proto Network-layer protocol (in host order)
+ * @ret efirc EFI status code
+ */
+static EFI_STATUS EFIAPI
+efi_snp_transmit ( EFI_SIMPLE_NETWORK_PROTOCOL *snp,
+ UINTN ll_header_len, UINTN len, VOID *data,
+ EFI_MAC_ADDRESS *ll_src, EFI_MAC_ADDRESS *ll_dest,
+ UINT16 *net_proto ) {
+ struct efi_snp_device *snpdev =
+ container_of ( snp, struct efi_snp_device, snp );
+ struct ll_protocol *ll_protocol = snpdev->netdev->ll_protocol;
+ struct io_buffer *iobuf;
+ int rc;
+ EFI_STATUS efirc;
+
+ DBGC2 ( snpdev, "SNPDEV %p TRANSMIT %p+%lx", snpdev, data, len );
+ if ( ll_header_len ) {
+ if ( ll_src ) {
+ DBGC2 ( snpdev, " src %s",
+ ll_protocol->ntoa ( ll_src ) );
+ }
+ if ( ll_dest ) {
+ DBGC2 ( snpdev, " dest %s",
+ ll_protocol->ntoa ( ll_dest ) );
+ }
+ if ( net_proto ) {
+ DBGC2 ( snpdev, " proto %04x", *net_proto );
+ }
+ }
+ DBGC2 ( snpdev, "\n" );
+
+ /* Sanity checks */
+ if ( ll_header_len ) {
+ if ( ll_header_len != ll_protocol->ll_header_len ) {
+ DBGC ( snpdev, "SNPDEV %p TX invalid header length "
+ "%ld\n", snpdev, ll_header_len );
+ efirc = EFI_INVALID_PARAMETER;
+ goto err_sanity;
+ }
+ if ( len < ll_header_len ) {
+ DBGC ( snpdev, "SNPDEV %p invalid packet length %ld\n",
+ snpdev, len );
+ efirc = EFI_BUFFER_TOO_SMALL;
+ goto err_sanity;
+ }
+ if ( ! ll_dest ) {
+ DBGC ( snpdev, "SNPDEV %p TX missing destination "
+ "address\n", snpdev );
+ efirc = EFI_INVALID_PARAMETER;
+ goto err_sanity;
+ }
+ if ( ! net_proto ) {
+ DBGC ( snpdev, "SNPDEV %p TX missing network "
+ "protocol\n", snpdev );
+ efirc = EFI_INVALID_PARAMETER;
+ goto err_sanity;
+ }
+ if ( ! ll_src )
+ ll_src = &snpdev->mode.CurrentAddress;
+ }
+
+ /* Allocate buffer */
+ iobuf = alloc_iob ( len );
+ if ( ! iobuf ) {
+ DBGC ( snpdev, "SNPDEV %p TX could not allocate %ld-byte "
+ "buffer\n", snpdev, len );
+ efirc = EFI_DEVICE_ERROR;
+ goto err_alloc_iob;
+ }
+ memcpy ( iob_put ( iobuf, len ), data, len );
+
+ /* Create link-layer header, if specified */
+ if ( ll_header_len ) {
+ iob_pull ( iobuf, ll_header_len );
+ if ( ( rc = ll_protocol->push ( iobuf, ll_dest, ll_src,
+ htons ( *net_proto ) )) != 0 ){
+ DBGC ( snpdev, "SNPDEV %p TX could not construct "
+ "header: %s\n", snpdev, strerror ( rc ) );
+ efirc = RC_TO_EFIRC ( rc );
+ goto err_ll_push;
+ }
+ }
+
+ /* Transmit packet */
+ if ( ( rc = netdev_tx ( snpdev->netdev, iobuf ) ) != 0 ) {
+ DBGC ( snpdev, "SNPDEV %p TX could not transmit: %s\n",
+ snpdev, strerror ( rc ) );
+ iobuf = NULL;
+ efirc = RC_TO_EFIRC ( rc );
+ goto err_tx;
+ }
+
+ /* Record transmission as outstanding */
+ snpdev->tx_count_interrupts++;
+ snpdev->tx_count_txbufs++;
+
+ return 0;
+
+ err_tx:
+ err_ll_push:
+ free_iob ( iobuf );
+ err_alloc_iob:
+ err_sanity:
+ return efirc;
+}
+
+/**
+ * Receive packet
+ *
+ * @v snp SNP interface
+ * @v ll_header_len Link-layer header length, if to be filled in
+ * @v len Length of data buffer
+ * @v data Data buffer
+ * @v ll_src Link-layer source address, if specified
+ * @v ll_dest Link-layer destination address, if specified
+ * @v net_proto Network-layer protocol (in host order)
+ * @ret efirc EFI status code
+ */
+static EFI_STATUS EFIAPI
+efi_snp_receive ( EFI_SIMPLE_NETWORK_PROTOCOL *snp,
+ UINTN *ll_header_len, UINTN *len, VOID *data,
+ EFI_MAC_ADDRESS *ll_src, EFI_MAC_ADDRESS *ll_dest,
+ UINT16 *net_proto ) {
+ struct efi_snp_device *snpdev =
+ container_of ( snp, struct efi_snp_device, snp );
+ struct ll_protocol *ll_protocol = snpdev->netdev->ll_protocol;
+ struct io_buffer *iobuf;
+ const void *iob_ll_dest;
+ const void *iob_ll_src;
+ uint16_t iob_net_proto;
+ int rc;
+ EFI_STATUS efirc;
+
+ DBGC2 ( snpdev, "SNPDEV %p RECEIVE %p(+%lx)", snpdev, data, *len );
+
+ /* Poll the network device */
+ efi_snp_poll ( snpdev );
+
+ /* Dequeue a packet, if one is available */
+ iobuf = netdev_rx_dequeue ( snpdev->netdev );
+ if ( ! iobuf ) {
+ DBGC2 ( snpdev, "\n" );
+ efirc = EFI_NOT_READY;
+ goto out_no_packet;
+ }
+ DBGC2 ( snpdev, "+%zx\n", iob_len ( iobuf ) );
+
+ /* Return packet to caller */
+ memcpy ( data, iobuf->data, iob_len ( iobuf ) );
+ *len = iob_len ( iobuf );
+
+ /* Attempt to decode link-layer header */
+ if ( ( rc = ll_protocol->pull ( iobuf, &iob_ll_dest, &iob_ll_src,
+ &iob_net_proto ) ) != 0 ) {
+ DBGC ( snpdev, "SNPDEV %p could not parse header: %s\n",
+ snpdev, strerror ( rc ) );
+ efirc = RC_TO_EFIRC ( rc );
+ goto out_bad_ll_header;
+ }
+
+ /* Return link-layer header parameters to caller, if required */
+ if ( ll_header_len )
+ *ll_header_len = ll_protocol->ll_header_len;
+ if ( ll_src )
+ memcpy ( ll_src, iob_ll_src, ll_protocol->ll_addr_len );
+ if ( ll_dest )
+ memcpy ( ll_dest, iob_ll_dest, ll_protocol->ll_addr_len );
+ if ( net_proto )
+ *net_proto = ntohs ( iob_net_proto );
+
+ efirc = 0;
+
+ out_bad_ll_header:
+ free_iob ( iobuf );
+out_no_packet:
+ return efirc;
+}
+
+/**
+ * Poll event
+ *
+ * @v event Event
+ * @v context Event context
+ */
+static VOID EFIAPI efi_snp_wait_for_packet ( EFI_EVENT event,
+ VOID *context ) {
+ EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+ struct efi_snp_device *snpdev = context;
+
+ DBGCP ( snpdev, "SNPDEV %p WAIT_FOR_PACKET\n", snpdev );
+
+ /* Do nothing unless the net device is open */
+ if ( ! ( snpdev->netdev->state & NETDEV_OPEN ) )
+ return;
+
+ /* Poll the network device */
+ efi_snp_poll ( snpdev );
+
+ /* Fire event if packets have been received */
+ if ( snpdev->rx_count_events != 0 ) {
+ DBGC2 ( snpdev, "SNPDEV %p firing WaitForPacket event\n",
+ snpdev );
+ bs->SignalEvent ( event );
+ snpdev->rx_count_events--;
+ }
+}
+
+/** SNP interface */
+static EFI_SIMPLE_NETWORK_PROTOCOL efi_snp_device_snp = {
+ .Revision = EFI_SIMPLE_NETWORK_PROTOCOL_REVISION,
+ .Start = efi_snp_start,
+ .Stop = efi_snp_stop,
+ .Initialize = efi_snp_initialize,
+ .Reset = efi_snp_reset,
+ .Shutdown = efi_snp_shutdown,
+ .ReceiveFilters = efi_snp_receive_filters,
+ .StationAddress = efi_snp_station_address,
+ .Statistics = efi_snp_statistics,
+ .MCastIpToMac = efi_snp_mcast_ip_to_mac,
+ .NvData = efi_snp_nvdata,
+ .GetStatus = efi_snp_get_status,
+ .Transmit = efi_snp_transmit,
+ .Receive = efi_snp_receive,
+};
+
+/**
+ * Locate net device corresponding to EFI device
+ *
+ * @v driver EFI driver
+ * @v device EFI device
+ * @ret netdev Net device, or NULL if not found
+ */
+static struct net_device *
+efi_snp_netdev ( EFI_DRIVER_BINDING_PROTOCOL *driver, EFI_HANDLE device ) {
+ EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+ union {
+ EFI_PCI_IO_PROTOCOL *pci;
+ void *interface;
+ } u;
+ UINTN pci_segment, pci_bus, pci_dev, pci_fn;
+ unsigned int pci_busdevfn;
+ struct net_device *netdev = NULL;
+ EFI_STATUS efirc;
+
+ /* See if device is a PCI device */
+ if ( ( efirc = bs->OpenProtocol ( device,
+ &efi_pci_io_protocol_guid,
+ &u.interface,
+ driver->DriverBindingHandle,
+ device,
+ EFI_OPEN_PROTOCOL_BY_DRIVER )) !=0 ){
+ DBGCP ( driver, "SNPDRV %p device %p is not a PCI device\n",
+ driver, device );
+ goto out_no_pci_io;
+ }
+
+ /* Get PCI bus:dev.fn address */
+ if ( ( efirc = u.pci->GetLocation ( u.pci, &pci_segment, &pci_bus,
+ &pci_dev, &pci_fn ) ) != 0 ) {
+ DBGC ( driver, "SNPDRV %p device %p could not get PCI "
+ "location: %lx\n", driver, device, efirc );
+ goto out_no_pci_location;
+ }
+ DBGCP ( driver, "SNPDRV %p device %p is PCI %04lx:%02lx:%02lx.%lx\n",
+ driver, device, pci_segment, pci_bus, pci_dev, pci_fn );
+
+ /* Look up corresponding network device */
+ pci_busdevfn = PCI_BUSDEVFN ( pci_bus, PCI_DEVFN ( pci_dev, pci_fn ) );
+ if ( ( netdev = find_netdev_by_location ( BUS_TYPE_PCI,
+ pci_busdevfn ) ) == NULL ) {
+ DBGCP ( driver, "SNPDRV %p device %p is not a gPXE network "
+ "device\n", driver, device );
+ goto out_no_netdev;
+ }
+ DBGC ( driver, "SNPDRV %p device %p is %s\n",
+ driver, device, netdev->name );
+
+ out_no_netdev:
+ out_no_pci_location:
+ bs->CloseProtocol ( device, &efi_pci_io_protocol_guid,
+ driver->DriverBindingHandle, device );
+ out_no_pci_io:
+ return netdev;
+}
+
+/**
+ * Locate SNP corresponding to EFI device
+ *
+ * @v driver EFI driver
+ * @v device EFI device
+ * @ret snp EFI SNP, or NULL if not found
+ */
+static struct efi_snp_device *
+efi_snp_snpdev ( EFI_DRIVER_BINDING_PROTOCOL *driver, EFI_HANDLE device ) {
+ EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+ union {
+ EFI_SIMPLE_NETWORK_PROTOCOL *snp;
+ void *interface;
+ } u;
+ struct efi_snp_device *snpdev;
+ EFI_STATUS efirc;
+
+ if ( ( efirc = bs->OpenProtocol ( device,
+ &efi_simple_network_protocol_guid,
+ &u.interface,
+ driver->DriverBindingHandle,
+ device,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL))!=0){
+ DBGC ( driver, "SNPDRV %p device %p could not locate SNP: "
+ "%lx\n", driver, device, efirc );
+ return NULL;
+ }
+
+ snpdev = container_of ( u.snp, struct efi_snp_device, snp );
+ DBGCP ( driver, "SNPDRV %p device %p is SNPDEV %p\n",
+ driver, device, snpdev );
+ return snpdev;
+}
+
+/**
+ * Check to see if driver supports a device
+ *
+ * @v driver EFI driver
+ * @v device EFI device
+ * @v child Path to child device, if any
+ * @ret efirc EFI status code
+ */
+static EFI_STATUS EFIAPI
+efi_snp_driver_supported ( EFI_DRIVER_BINDING_PROTOCOL *driver,
+ EFI_HANDLE device,
+ EFI_DEVICE_PATH_PROTOCOL *child ) {
+ struct net_device *netdev;
+
+ DBGCP ( driver, "SNPDRV %p DRIVER_SUPPORTED %p (%p)\n",
+ driver, device, child );
+
+ netdev = efi_snp_netdev ( driver, device );
+ return ( netdev ? 0 : EFI_UNSUPPORTED );
+}
+
+/**
+ * Attach driver to device
+ *
+ * @v driver EFI driver
+ * @v device EFI device
+ * @v child Path to child device, if any
+ * @ret efirc EFI status code
+ */
+static EFI_STATUS EFIAPI
+efi_snp_driver_start ( EFI_DRIVER_BINDING_PROTOCOL *driver,
+ EFI_HANDLE device,
+ EFI_DEVICE_PATH_PROTOCOL *child ) {
+ EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+ struct efi_snp_device *snpdev;
+ struct net_device *netdev;
+ EFI_STATUS efirc;
+
+ DBGCP ( driver, "SNPDRV %p DRIVER_START %p (%p)\n",
+ driver, device, child );
+
+ /* Allocate the SNP device */
+ snpdev = zalloc ( sizeof ( *snpdev ) );
+ if ( ! snpdev ) {
+ efirc = EFI_OUT_OF_RESOURCES;
+ goto err_alloc_snp;
+ }
+
+ /* Identify the net device */
+ netdev = efi_snp_netdev ( driver, device );
+ if ( ! netdev ) {
+ DBGC ( snpdev, "SNPDEV %p cannot find netdev for device %p\n",
+ snpdev, device );
+ efirc = EFI_UNSUPPORTED;
+ goto err_no_netdev;
+ }
+ snpdev->netdev = netdev_get ( netdev );
+
+ /* Sanity check */
+ if ( netdev->ll_protocol->ll_addr_len > sizeof ( EFI_MAC_ADDRESS ) ) {
+ DBGC ( snpdev, "SNPDEV %p cannot support link-layer address "
+ "length %zd for %s\n", snpdev,
+ netdev->ll_protocol->ll_addr_len, netdev->name );
+ efirc = EFI_INVALID_PARAMETER;
+ goto err_ll_addr_len;
+ }
+
+ /* Populate the SNP structure */
+ memcpy ( &snpdev->snp, &efi_snp_device_snp, sizeof ( snpdev->snp ) );
+ snpdev->snp.Mode = &snpdev->mode;
+ if ( ( efirc = bs->CreateEvent ( EVT_NOTIFY_WAIT, TPL_NOTIFY,
+ efi_snp_wait_for_packet, snpdev,
+ &snpdev->snp.WaitForPacket ) ) != 0 ){
+ DBGC ( snpdev, "SNPDEV %p could not create event: %lx\n",
+ snpdev, efirc );
+ goto err_create_event;
+ }
+
+ /* Populate the SNP mode structure */
+ snpdev->mode.State = EfiSimpleNetworkStopped;
+ efi_snp_set_mode ( snpdev );
+
+ /* Install the SNP */
+ if ( ( efirc = bs->InstallProtocolInterface ( &device,
+ &efi_simple_network_protocol_guid,
+ EFI_NATIVE_INTERFACE, &snpdev->snp ) ) != 0 ) {
+ DBGC ( snpdev, "SNPDEV %p could not install protocol: %lx\n",
+ snpdev, efirc );
+ goto err_install_protocol_interface;
+ }
+
+ DBGC ( snpdev, "SNPDEV %p installed for %s on device %p\n",
+ snpdev, netdev->name, device );
+ return 0;
+
+ bs->UninstallProtocolInterface ( device,
+ &efi_simple_network_protocol_guid,
+ &snpdev->snp );
+ err_install_protocol_interface:
+ bs->CloseEvent ( snpdev->snp.WaitForPacket );
+ err_create_event:
+ err_ll_addr_len:
+ netdev_put ( netdev );
+ err_no_netdev:
+ free ( snpdev );
+ err_alloc_snp:
+ return efirc;
+}
+
+/**
+ * Detach driver from device
+ *
+ * @v driver EFI driver
+ * @v device EFI device
+ * @v num_children Number of child devices
+ * @v children List of child devices
+ * @ret efirc EFI status code
+ */
+static EFI_STATUS EFIAPI
+efi_snp_driver_stop ( EFI_DRIVER_BINDING_PROTOCOL *driver,
+ EFI_HANDLE device,
+ UINTN num_children,
+ EFI_HANDLE *children ) {
+ EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+ struct efi_snp_device *snpdev;
+
+ DBGCP ( driver, "SNPDRV %p DRIVER_STOP %p (%ld %p)\n",
+ driver, device, num_children, children );
+
+ /* Locate SNP device */
+ snpdev = efi_snp_snpdev ( driver, device );
+ if ( ! snpdev ) {
+ DBGC ( driver, "SNPDRV %p device %p could not find SNPDEV\n",
+ driver, device );
+ return EFI_DEVICE_ERROR;
+ }
+
+ /* Uninstall the SNP */
+ bs->UninstallProtocolInterface ( device,
+ &efi_simple_network_protocol_guid,
+ &snpdev->snp );
+ bs->CloseEvent ( snpdev->snp.WaitForPacket );
+ netdev_put ( snpdev->netdev );
+ free ( snpdev );
+ return 0;
+}
+
+/** EFI SNP driver binding */
+static EFI_DRIVER_BINDING_PROTOCOL efi_snp_binding = {
+ efi_snp_driver_supported,
+ efi_snp_driver_start,
+ efi_snp_driver_stop,
+ 0x10,
+ NULL,
+ NULL
+};
+
+/**
+ * Install EFI SNP driver
+ *
+ * @ret rc Return status code
+ */
+int efi_snp_install ( void ) {
+ EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+ EFI_DRIVER_BINDING_PROTOCOL *driver = &efi_snp_binding;
+ EFI_STATUS efirc;
+
+ driver->ImageHandle = efi_image_handle;
+ if ( ( efirc = bs->InstallProtocolInterface (
+ &driver->DriverBindingHandle,
+ &efi_driver_binding_protocol_guid,
+ EFI_NATIVE_INTERFACE,
+ driver ) ) != 0 ) {
+ DBGC ( driver, "SNPDRV %p could not install driver binding: "
+ "%lx\n", driver, efirc );
+ return EFIRC_TO_RC ( efirc );
+ }
+
+ DBGC ( driver, "SNPDRV %p driver binding installed as %p\n",
+ driver, driver->DriverBindingHandle );
+ return 0;
+}
diff --git a/gpxe/src/interface/efi/efi_timer.c b/gpxe/src/interface/efi/efi_timer.c
new file mode 100644
index 00000000..b4e54a65
--- /dev/null
+++ b/gpxe/src/interface/efi/efi_timer.c
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2008 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 <limits.h>
+#include <assert.h>
+#include <unistd.h>
+#include <gpxe/timer.h>
+#include <gpxe/efi/efi.h>
+#include <gpxe/efi/Protocol/Cpu.h>
+
+/** @file
+ *
+ * gPXE timer API for EFI
+ *
+ */
+
+/** Scale factor to apply to CPU timer 0
+ *
+ * The timer is scaled down in order to ensure that reasonable values
+ * for "number of ticks" don't exceed the size of an unsigned long.
+ */
+#define EFI_TIMER0_SHIFT 12
+
+/** Calibration time */
+#define EFI_CALIBRATE_DELAY_MS 1
+
+/** CPU protocol */
+static EFI_CPU_ARCH_PROTOCOL *cpu_arch;
+EFI_REQUIRE_PROTOCOL ( EFI_CPU_ARCH_PROTOCOL, &cpu_arch );
+
+/**
+ * Delay for a fixed number of microseconds
+ *
+ * @v usecs Number of microseconds for which to delay
+ */
+static void efi_udelay ( unsigned long usecs ) {
+ EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+ EFI_STATUS efirc;
+
+ if ( ( efirc = bs->Stall ( usecs ) ) != 0 ) {
+ DBG ( "EFI could not delay for %ldus: %lx\n",
+ usecs, efirc );
+ /* Probably screwed */
+ }
+}
+
+/**
+ * Get current system time in ticks
+ *
+ * @ret ticks Current time, in ticks
+ */
+static unsigned long efi_currticks ( void ) {
+ UINT64 time;
+ EFI_STATUS efirc;
+
+ /* Read CPU timer 0 (TSC) */
+ if ( ( efirc = cpu_arch->GetTimerValue ( cpu_arch, 0, &time,
+ NULL ) ) != 0 ) {
+ DBG ( "EFI could not read CPU timer: %lx\n", efirc );
+ /* Probably screwed */
+ return -1UL;
+ }
+
+ return ( time >> EFI_TIMER0_SHIFT );
+}
+
+/**
+ * Get number of ticks per second
+ *
+ * @ret ticks_per_sec Number of ticks per second
+ */
+static unsigned long efi_ticks_per_sec ( void ) {
+ static unsigned long ticks_per_sec = 0;
+
+ /* Calibrate timer, if necessary. EFI does nominally provide
+ * the timer speed via the (optional) TimerPeriod parameter to
+ * the GetTimerValue() call, but it gets the speed slightly
+ * wrong. By up to three orders of magnitude. Not helpful.
+ */
+ if ( ! ticks_per_sec ) {
+ unsigned long start;
+ unsigned long elapsed;
+
+ DBG ( "Calibrating EFI timer with a %d ms delay\n",
+ EFI_CALIBRATE_DELAY_MS );
+ start = currticks();
+ mdelay ( EFI_CALIBRATE_DELAY_MS );
+ elapsed = ( currticks() - start );
+ ticks_per_sec = ( elapsed * ( 1000 / EFI_CALIBRATE_DELAY_MS ));
+ DBG ( "EFI CPU timer calibrated at %ld ticks in %d ms (%ld "
+ "ticks/sec)\n", elapsed, EFI_CALIBRATE_DELAY_MS,
+ ticks_per_sec );
+ }
+
+ return ticks_per_sec;
+}
+
+PROVIDE_TIMER ( efi, udelay, efi_udelay );
+PROVIDE_TIMER ( efi, currticks, efi_currticks );
+PROVIDE_TIMER ( efi, ticks_per_sec, efi_ticks_per_sec );
diff --git a/gpxe/src/interface/efi/efi_uaccess.c b/gpxe/src/interface/efi/efi_uaccess.c
new file mode 100644
index 00000000..1c54c031
--- /dev/null
+++ b/gpxe/src/interface/efi/efi_uaccess.c
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2008 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 <gpxe/uaccess.h>
+#include <gpxe/efi/efi.h>
+
+/** @file
+ *
+ * gPXE user access API for EFI
+ *
+ */
+
+PROVIDE_UACCESS_INLINE ( efi, phys_to_user );
+PROVIDE_UACCESS_INLINE ( efi, user_to_phys );
+PROVIDE_UACCESS_INLINE ( efi, virt_to_user );
+PROVIDE_UACCESS_INLINE ( efi, user_to_virt );
+PROVIDE_UACCESS_INLINE ( efi, userptr_add );
+PROVIDE_UACCESS_INLINE ( efi, memcpy_user );
+PROVIDE_UACCESS_INLINE ( efi, memmove_user );
+PROVIDE_UACCESS_INLINE ( efi, memset_user );
+PROVIDE_UACCESS_INLINE ( efi, strlen_user );
+PROVIDE_UACCESS_INLINE ( efi, memchr_user );
diff --git a/gpxe/src/interface/efi/efi_umalloc.c b/gpxe/src/interface/efi/efi_umalloc.c
new file mode 100644
index 00000000..d7357a1d
--- /dev/null
+++ b/gpxe/src/interface/efi/efi_umalloc.c
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2008 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 <assert.h>
+#include <gpxe/umalloc.h>
+#include <gpxe/efi/efi.h>
+
+/** @file
+ *
+ * gPXE user memory allocation API for EFI
+ *
+ */
+
+/** Equivalent of NOWHERE for user pointers */
+#define UNOWHERE ( ~UNULL )
+
+/**
+ * Reallocate external memory
+ *
+ * @v old_ptr Memory previously allocated by umalloc(), or UNULL
+ * @v new_size Requested size
+ * @ret new_ptr Allocated memory, or UNULL
+ *
+ * Calling realloc() with a new size of zero is a valid way to free a
+ * memory block.
+ */
+static userptr_t efi_urealloc ( userptr_t old_ptr, size_t new_size ) {
+ EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+ EFI_PHYSICAL_ADDRESS phys_addr;
+ unsigned int new_pages, old_pages;
+ userptr_t new_ptr = UNOWHERE;
+ size_t old_size;
+ EFI_STATUS efirc;
+
+ /* Allocate new memory if necessary. If allocation fails,
+ * return without touching the old block.
+ */
+ if ( new_size ) {
+ new_pages = ( EFI_SIZE_TO_PAGES ( new_size ) + 1 );
+ if ( ( efirc = bs->AllocatePages ( AllocateAnyPages,
+ EfiBootServicesData,
+ new_pages,
+ &phys_addr ) ) != 0 ) {
+ DBG ( "EFI could not allocate %d pages: %lx\n",
+ new_pages, efirc );
+ return UNULL;
+ }
+ assert ( phys_addr != 0 );
+ new_ptr = phys_to_user ( phys_addr + EFI_PAGE_SIZE );
+ copy_to_user ( new_ptr, -EFI_PAGE_SIZE,
+ &new_size, sizeof ( new_size ) );
+ DBG ( "EFI allocated %d pages at %llx\n",
+ new_pages, phys_addr );
+ }
+
+ /* Copy across relevant part of the old data region (if any),
+ * then free it. Note that at this point either (a) new_ptr
+ * is valid, or (b) new_size is 0; either way, the memcpy() is
+ * valid.
+ */
+ if ( old_ptr && ( old_ptr != UNOWHERE ) ) {
+ copy_from_user ( &old_size, old_ptr, -EFI_PAGE_SIZE,
+ sizeof ( old_size ) );
+ memcpy_user ( new_ptr, 0, old_ptr, 0,
+ ( (old_size < new_size) ? old_size : new_size ));
+ old_pages = ( EFI_SIZE_TO_PAGES ( old_size ) + 1 );
+ phys_addr = user_to_phys ( old_ptr, -EFI_PAGE_SIZE );
+ if ( ( efirc = bs->FreePages ( phys_addr, old_pages ) ) != 0 ){
+ DBG ( "EFI could not free %d pages at %llx: %lx\n",
+ old_pages, phys_addr, efirc );
+ /* Not fatal; we have leaked memory but successfully
+ * allocated (if asked to do so).
+ */
+ }
+ DBG ( "EFI freed %d pages at %llx\n", old_pages, phys_addr );
+ }
+
+ return new_ptr;
+}
+
+PROVIDE_UMALLOC ( efi, urealloc, efi_urealloc );
diff --git a/gpxe/src/interface/pxe/pxe_undi.c b/gpxe/src/interface/pxe/pxe_undi.c
index 5d06f2d8..4e4a3da0 100644
--- a/gpxe/src/interface/pxe/pxe_undi.c
+++ b/gpxe/src/interface/pxe/pxe_undi.c
@@ -199,9 +199,10 @@ PXENV_EXIT_t pxenv_undi_transmit ( struct s_PXENV_UNDI_TRANSMIT
struct DataBlk *datablk;
struct io_buffer *iobuf;
struct net_protocol *net_protocol;
+ struct ll_protocol *ll_protocol = pxe_netdev->ll_protocol;
char destaddr[MAX_LL_ADDR_LEN];
const void *ll_dest;
- size_t ll_hlen = pxe_netdev->ll_protocol->ll_header_len;
+ size_t ll_hlen = ll_protocol->ll_header_len;
size_t len;
unsigned int i;
int rc;
@@ -259,17 +260,17 @@ PXENV_EXIT_t pxenv_undi_transmit ( struct s_PXENV_UNDI_TRANSMIT
copy_from_real ( destaddr,
undi_transmit->DestAddr.segment,
undi_transmit->DestAddr.offset,
- pxe_netdev->ll_protocol->ll_addr_len );
+ ll_protocol->ll_addr_len );
ll_dest = destaddr;
} else {
DBG ( " BCAST" );
- ll_dest = pxe_netdev->ll_protocol->ll_broadcast;
+ ll_dest = ll_protocol->ll_broadcast;
}
/* Add link-layer header */
- if ( ( rc = pxe_netdev->ll_protocol->push ( iobuf, pxe_netdev,
- net_protocol,
- ll_dest )) != 0 ){
+ if ( ( rc = ll_protocol->push ( iobuf, ll_dest,
+ pxe_netdev->ll_addr,
+ net_protocol->net_proto ))!=0){
free_iob ( iobuf );
undi_transmit->Status = PXENV_STATUS ( rc );
return PXENV_EXIT_FAILURE;
@@ -391,10 +392,10 @@ PXENV_EXIT_t pxenv_undi_get_statistics ( struct s_PXENV_UNDI_GET_STATISTICS
*undi_get_statistics ) {
DBG ( "PXENV_UNDI_GET_STATISTICS" );
- undi_get_statistics->XmtGoodFrames = pxe_netdev->stats.tx_ok;
- undi_get_statistics->RcvGoodFrames = pxe_netdev->stats.rx_ok;
- undi_get_statistics->RcvCRCErrors = pxe_netdev->stats.rx_err;
- undi_get_statistics->RcvResourceErrors = pxe_netdev->stats.rx_err;
+ undi_get_statistics->XmtGoodFrames = pxe_netdev->tx_stats.good;
+ undi_get_statistics->RcvGoodFrames = pxe_netdev->rx_stats.good;
+ undi_get_statistics->RcvCRCErrors = pxe_netdev->rx_stats.bad;
+ undi_get_statistics->RcvResourceErrors = pxe_netdev->rx_stats.bad;
undi_get_statistics->Status = PXENV_STATUS_SUCCESS;
return PXENV_EXIT_SUCCESS;
@@ -408,7 +409,8 @@ PXENV_EXIT_t pxenv_undi_clear_statistics ( struct s_PXENV_UNDI_CLEAR_STATISTICS
*undi_clear_statistics ) {
DBG ( "PXENV_UNDI_CLEAR_STATISTICS" );
- memset ( &pxe_netdev->stats, 0, sizeof ( pxe_netdev->stats ) );
+ memset ( &pxe_netdev->tx_stats, 0, sizeof ( pxe_netdev->tx_stats ) );
+ memset ( &pxe_netdev->rx_stats, 0, sizeof ( pxe_netdev->rx_stats ) );
undi_clear_statistics->Status = PXENV_STATUS_SUCCESS;
return PXENV_EXIT_SUCCESS;
@@ -545,6 +547,7 @@ PXENV_EXIT_t pxenv_undi_isr ( struct s_PXENV_UNDI_ISR *undi_isr ) {
struct io_buffer *iobuf;
size_t len;
struct ll_protocol *ll_protocol;
+ const void *ll_dest;
const void *ll_source;
uint16_t net_proto;
size_t ll_hlen;
@@ -625,9 +628,8 @@ PXENV_EXIT_t pxenv_undi_isr ( struct s_PXENV_UNDI_ISR *undi_isr ) {
/* Strip link-layer header */
ll_protocol = pxe_netdev->ll_protocol;
- if ( ( rc = ll_protocol->pull ( iobuf, pxe_netdev,
- &net_proto,
- &ll_source ) ) != 0 ) {
+ if ( ( rc = ll_protocol->pull ( iobuf, &ll_dest, &ll_source,
+ &net_proto ) ) != 0 ) {
/* Assume unknown net_proto and no ll_source */
net_proto = 0;
ll_source = NULL;
diff --git a/gpxe/src/net/aoe.c b/gpxe/src/net/aoe.c
index e3f84e5a..ec3814bf 100644
--- a/gpxe/src/net/aoe.c
+++ b/gpxe/src/net/aoe.c
@@ -94,6 +94,13 @@ static int aoe_send_command ( struct aoe_session *aoe ) {
return -ENETUNREACH;
}
+ /* If we are transmitting anything that requires a response,
+ * start the retransmission timer. Do this before attempting
+ * to allocate the I/O buffer, in case allocation itself
+ * fails.
+ */
+ start_timer ( &aoe->timer );
+
/* Calculate count and data_out_len for this subcommand */
count = command->cb.count.native;
if ( count > AOE_MAX_COUNT )
@@ -101,8 +108,8 @@ static int aoe_send_command ( struct aoe_session *aoe ) {
data_out_len = ( command->data_out ? ( count * ATA_SECTOR_SIZE ) : 0 );
/* Create outgoing I/O buffer */
- iobuf = alloc_iob ( ETH_HLEN + sizeof ( *aoehdr ) + sizeof ( *aoecmd ) +
- data_out_len );
+ iobuf = alloc_iob ( ETH_HLEN + sizeof ( *aoehdr ) +
+ sizeof ( *aoecmd ) + data_out_len );
if ( ! iobuf )
return -ENOMEM;
iob_reserve ( iobuf, ETH_HLEN );
@@ -133,7 +140,6 @@ static int aoe_send_command ( struct aoe_session *aoe ) {
aoe->command_offset, data_out_len );
/* Send packet */
- start_timer ( &aoe->timer );
return net_tx ( iobuf, aoe->netdev, &aoe_protocol, aoe->target );
}
@@ -231,7 +237,8 @@ static int aoe_rx_response ( struct aoe_session *aoe, struct aoehdr *aoehdr,
* @ret rc Return status code
*
*/
-static int aoe_rx ( struct io_buffer *iobuf, struct net_device *netdev __unused,
+static int aoe_rx ( struct io_buffer *iobuf,
+ struct net_device *netdev __unused,
const void *ll_source ) {
struct aoehdr *aoehdr = iobuf->data;
unsigned int len = iob_len ( iobuf );
diff --git a/gpxe/src/net/ethernet.c b/gpxe/src/net/ethernet.c
index 7b1c496f..3b289705 100644
--- a/gpxe/src/net/ethernet.c
+++ b/gpxe/src/net/ethernet.c
@@ -24,6 +24,7 @@
#include <assert.h>
#include <gpxe/if_arp.h>
#include <gpxe/if_ether.h>
+#include <gpxe/in.h>
#include <gpxe/netdevice.h>
#include <gpxe/iobuf.h>
#include <gpxe/ethernet.h>
@@ -41,19 +42,19 @@ static uint8_t eth_broadcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
* Add Ethernet link-layer header
*
* @v iobuf I/O buffer
- * @v netdev Network device
- * @v net_protocol Network-layer protocol
* @v ll_dest Link-layer destination address
+ * @v ll_source Source link-layer address
+ * @v net_proto Network-layer protocol, in network-byte order
+ * @ret rc Return status code
*/
-static int eth_push ( struct io_buffer *iobuf, struct net_device *netdev,
- struct net_protocol *net_protocol,
- const void *ll_dest ) {
+static int eth_push ( struct io_buffer *iobuf, const void *ll_dest,
+ const void *ll_source, uint16_t net_proto ) {
struct ethhdr *ethhdr = iob_push ( iobuf, sizeof ( *ethhdr ) );
/* Build Ethernet header */
memcpy ( ethhdr->h_dest, ll_dest, ETH_ALEN );
- memcpy ( ethhdr->h_source, netdev->ll_addr, ETH_ALEN );
- ethhdr->h_protocol = net_protocol->net_proto;
+ memcpy ( ethhdr->h_source, ll_source, ETH_ALEN );
+ ethhdr->h_protocol = net_proto;
return 0;
}
@@ -62,14 +63,13 @@ static int eth_push ( struct io_buffer *iobuf, struct net_device *netdev,
* Remove Ethernet link-layer header
*
* @v iobuf I/O buffer
- * @v netdev Network device
- * @v net_proto Network-layer protocol, in network-byte order
- * @v ll_source Source link-layer address
+ * @ret ll_dest Link-layer destination address
+ * @ret ll_source Source link-layer address
+ * @ret net_proto Network-layer protocol, in network-byte order
* @ret rc Return status code
*/
-static int eth_pull ( struct io_buffer *iobuf,
- struct net_device *netdev __unused,
- uint16_t *net_proto, const void **ll_source ) {
+static int eth_pull ( struct io_buffer *iobuf, const void **ll_dest,
+ const void **ll_source, uint16_t *net_proto ) {
struct ethhdr *ethhdr = iobuf->data;
/* Sanity check */
@@ -83,8 +83,9 @@ static int eth_pull ( struct io_buffer *iobuf,
iob_pull ( iobuf, sizeof ( *ethhdr ) );
/* Fill in required fields */
- *net_proto = ethhdr->h_protocol;
+ *ll_dest = ethhdr->h_dest;
*ll_source = ethhdr->h_source;
+ *net_proto = ethhdr->h_protocol;
return 0;
}
@@ -92,8 +93,8 @@ static int eth_pull ( struct io_buffer *iobuf,
/**
* Transcribe Ethernet address
*
- * @v ll_addr Link-layer address
- * @ret string Link-layer address in human-readable format
+ * @v ll_addr Link-layer address
+ * @ret string Link-layer address in human-readable format
*/
const char * eth_ntoa ( const void *ll_addr ) {
static char buf[18]; /* "00:00:00:00:00:00" */
@@ -105,6 +106,32 @@ const char * eth_ntoa ( const void *ll_addr ) {
return buf;
}
+/**
+ * Hash multicast address
+ *
+ * @v af Address family
+ * @v net_addr Network-layer address
+ * @v ll_addr Link-layer address to fill in
+ * @ret rc Return status code
+ */
+static int eth_mc_hash ( unsigned int af, const void *net_addr,
+ void *ll_addr ) {
+ const uint8_t *net_addr_bytes = net_addr;
+ uint8_t *ll_addr_bytes = ll_addr;
+
+ switch ( af ) {
+ case AF_INET:
+ ll_addr_bytes[0] = 0x01;
+ ll_addr_bytes[1] = 0x00;
+ ll_addr_bytes[2] = 0x5e;
+ ll_addr_bytes[3] = net_addr_bytes[1] & 0x7f;
+ ll_addr_bytes[4] = net_addr_bytes[2];
+ ll_addr_bytes[5] = net_addr_bytes[3];
+ default:
+ return -ENOTSUP;
+ }
+}
+
/** Ethernet protocol */
struct ll_protocol ethernet_protocol __ll_protocol = {
.name = "Ethernet",
@@ -115,4 +142,5 @@ struct ll_protocol ethernet_protocol __ll_protocol = {
.push = eth_push,
.pull = eth_pull,
.ntoa = eth_ntoa,
+ .mc_hash = eth_mc_hash,
};
diff --git a/gpxe/src/net/infiniband.c b/gpxe/src/net/infiniband.c
index ab76742e..fb6fca7d 100644
--- a/gpxe/src/net/infiniband.c
+++ b/gpxe/src/net/infiniband.c
@@ -46,10 +46,12 @@ struct list_head ib_devices = LIST_HEAD_INIT ( ib_devices );
*
* @v ibdev Infiniband device
* @v num_cqes Number of completion queue entries
+ * @v op Completion queue operations
* @ret cq New completion queue
*/
-struct ib_completion_queue * ib_create_cq ( struct ib_device *ibdev,
- unsigned int num_cqes ) {
+struct ib_completion_queue *
+ib_create_cq ( struct ib_device *ibdev, unsigned int num_cqes,
+ struct ib_completion_queue_operations *op ) {
struct ib_completion_queue *cq;
int rc;
@@ -58,22 +60,28 @@ struct ib_completion_queue * ib_create_cq ( struct ib_device *ibdev,
/* Allocate and initialise data structure */
cq = zalloc ( sizeof ( *cq ) );
if ( ! cq )
- return NULL;
+ goto err_alloc_cq;
cq->num_cqes = num_cqes;
INIT_LIST_HEAD ( &cq->work_queues );
+ cq->op = op;
/* Perform device-specific initialisation and get CQN */
if ( ( rc = ibdev->op->create_cq ( ibdev, cq ) ) != 0 ) {
DBGC ( ibdev, "IBDEV %p could not initialise completion "
"queue: %s\n", ibdev, strerror ( rc ) );
- free ( cq );
- return NULL;
+ goto err_dev_create_cq;
}
DBGC ( ibdev, "IBDEV %p created %d-entry completion queue %p (%p) "
"with CQN %#lx\n", ibdev, num_cqes, cq,
ib_cq_get_drvdata ( cq ), cq->cqn );
return cq;
+
+ ibdev->op->destroy_cq ( ibdev, cq );
+ err_dev_create_cq:
+ free ( cq );
+ err_alloc_cq:
+ return NULL;
}
/**
@@ -120,7 +128,9 @@ struct ib_queue_pair * ib_create_qp ( struct ib_device *ibdev,
( num_recv_wqes * sizeof ( qp->recv.iobufs[0] ) ) );
qp = zalloc ( total_size );
if ( ! qp )
- return NULL;
+ goto err_alloc_qp;
+ qp->ibdev = ibdev;
+ list_add ( &qp->list, &ibdev->qps );
qp->qkey = qkey;
qp->send.qp = qp;
qp->send.is_send = 1;
@@ -134,15 +144,13 @@ struct ib_queue_pair * ib_create_qp ( struct ib_device *ibdev,
qp->recv.num_wqes = num_recv_wqes;
qp->recv.iobufs = ( ( ( void * ) qp ) + sizeof ( *qp ) +
( num_send_wqes * sizeof ( qp->send.iobufs[0] ) ));
+ INIT_LIST_HEAD ( &qp->mgids );
/* Perform device-specific initialisation and get QPN */
if ( ( rc = ibdev->op->create_qp ( ibdev, qp ) ) != 0 ) {
DBGC ( ibdev, "IBDEV %p could not initialise queue pair: "
"%s\n", ibdev, strerror ( rc ) );
- list_del ( &qp->send.list );
- list_del ( &qp->recv.list );
- free ( qp );
- return NULL;
+ goto err_dev_create_qp;
}
DBGC ( ibdev, "IBDEV %p created queue pair %p (%p) with QPN %#lx\n",
@@ -154,6 +162,15 @@ struct ib_queue_pair * ib_create_qp ( struct ib_device *ibdev,
ibdev, qp->qpn, num_recv_wqes, qp->recv.iobufs,
( ( ( void * ) qp ) + total_size ) );
return qp;
+
+ ibdev->op->destroy_qp ( ibdev, qp );
+ err_dev_create_qp:
+ list_del ( &qp->send.list );
+ list_del ( &qp->recv.list );
+ list_del ( &qp->list );
+ free ( qp );
+ err_alloc_qp:
+ return NULL;
}
/**
@@ -190,15 +207,80 @@ int ib_modify_qp ( struct ib_device *ibdev, struct ib_queue_pair *qp,
* @v qp Queue pair
*/
void ib_destroy_qp ( struct ib_device *ibdev, struct ib_queue_pair *qp ) {
+ struct io_buffer *iobuf;
+ unsigned int i;
+
DBGC ( ibdev, "IBDEV %p destroying QPN %#lx\n",
ibdev, qp->qpn );
+
+ assert ( list_empty ( &qp->mgids ) );
+
+ /* Perform device-specific destruction */
ibdev->op->destroy_qp ( ibdev, qp );
+
+ /* Complete any remaining I/O buffers with errors */
+ for ( i = 0 ; i < qp->send.num_wqes ; i++ ) {
+ if ( ( iobuf = qp->send.iobufs[i] ) != NULL )
+ ib_complete_send ( ibdev, qp, iobuf, -ECANCELED );
+ }
+ for ( i = 0 ; i < qp->recv.num_wqes ; i++ ) {
+ if ( ( iobuf = qp->recv.iobufs[i] ) != NULL ) {
+ ib_complete_recv ( ibdev, qp, NULL, iobuf,
+ -ECANCELED );
+ }
+ }
+
+ /* Remove work queues from completion queue */
list_del ( &qp->send.list );
list_del ( &qp->recv.list );
+
+ /* Free QP */
+ list_del ( &qp->list );
free ( qp );
}
/**
+ * Find queue pair by QPN
+ *
+ * @v ibdev Infiniband device
+ * @v qpn Queue pair number
+ * @ret qp Queue pair, or NULL
+ */
+struct ib_queue_pair * ib_find_qp_qpn ( struct ib_device *ibdev,
+ unsigned long qpn ) {
+ struct ib_queue_pair *qp;
+
+ list_for_each_entry ( qp, &ibdev->qps, list ) {
+ if ( qp->qpn == qpn )
+ return qp;
+ }
+ return NULL;
+}
+
+/**
+ * Find queue pair by multicast GID
+ *
+ * @v ibdev Infiniband device
+ * @v gid Multicast GID
+ * @ret qp Queue pair, or NULL
+ */
+struct ib_queue_pair * ib_find_qp_mgid ( struct ib_device *ibdev,
+ struct ib_gid *gid ) {
+ struct ib_queue_pair *qp;
+ struct ib_multicast_gid *mgid;
+
+ list_for_each_entry ( qp, &ibdev->qps, list ) {
+ list_for_each_entry ( mgid, &qp->mgids, list ) {
+ if ( memcmp ( &mgid->gid, gid,
+ sizeof ( mgid->gid ) ) == 0 ) {
+ return qp;
+ }
+ }
+ }
+ return NULL;
+}
+
+/**
* Find work queue belonging to completion queue
*
* @v cq Completion queue
@@ -217,142 +299,158 @@ struct ib_work_queue * ib_find_wq ( struct ib_completion_queue *cq,
return NULL;
}
-/***************************************************************************
- *
- * Management datagram operations
- *
- ***************************************************************************
- */
-
/**
- * Get port information
+ * Post send work queue entry
*
* @v ibdev Infiniband device
- * @v port_info Port information datagram to fill in
+ * @v qp Queue pair
+ * @v av Address vector
+ * @v iobuf I/O buffer
* @ret rc Return status code
*/
-static int ib_get_port_info ( struct ib_device *ibdev,
- struct ib_mad_port_info *port_info ) {
- struct ib_mad_hdr *hdr = &port_info->mad_hdr;
+int ib_post_send ( struct ib_device *ibdev, struct ib_queue_pair *qp,
+ struct ib_address_vector *av,
+ struct io_buffer *iobuf ) {
int rc;
- /* Construct MAD */
- memset ( port_info, 0, sizeof ( *port_info ) );
- hdr->base_version = IB_MGMT_BASE_VERSION;
- hdr->mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED;
- hdr->class_version = 1;
- hdr->method = IB_MGMT_METHOD_GET;
- hdr->attr_id = htons ( IB_SMP_ATTR_PORT_INFO );
- hdr->attr_mod = htonl ( ibdev->port );
-
- if ( ( rc = ib_mad ( ibdev, hdr, sizeof ( *port_info ) ) ) != 0 ) {
- DBGC ( ibdev, "IBDEV %p could not get port info: %s\n",
- ibdev, strerror ( rc ) );
+ /* Check queue fill level */
+ if ( qp->send.fill >= qp->send.num_wqes ) {
+ DBGC ( ibdev, "IBDEV %p QPN %#lx send queue full\n",
+ ibdev, qp->qpn );
+ return -ENOBUFS;
+ }
+
+ /* Post to hardware */
+ if ( ( rc = ibdev->op->post_send ( ibdev, qp, av, iobuf ) ) != 0 ) {
+ DBGC ( ibdev, "IBDEV %p QPN %#lx could not post send WQE: "
+ "%s\n", ibdev, qp->qpn, strerror ( rc ) );
return rc;
}
+
+ qp->send.fill++;
return 0;
}
/**
- * Get GUID information
+ * Post receive work queue entry
*
* @v ibdev Infiniband device
- * @v guid_info GUID information datagram to fill in
+ * @v qp Queue pair
+ * @v iobuf I/O buffer
* @ret rc Return status code
*/
-static int ib_get_guid_info ( struct ib_device *ibdev,
- struct ib_mad_guid_info *guid_info ) {
- struct ib_mad_hdr *hdr = &guid_info->mad_hdr;
+int ib_post_recv ( struct ib_device *ibdev, struct ib_queue_pair *qp,
+ struct io_buffer *iobuf ) {
int rc;
- /* Construct MAD */
- memset ( guid_info, 0, sizeof ( *guid_info ) );
- hdr->base_version = IB_MGMT_BASE_VERSION;
- hdr->mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED;
- hdr->class_version = 1;
- hdr->method = IB_MGMT_METHOD_GET;
- hdr->attr_id = htons ( IB_SMP_ATTR_GUID_INFO );
+ /* Check queue fill level */
+ if ( qp->recv.fill >= qp->recv.num_wqes ) {
+ DBGC ( ibdev, "IBDEV %p QPN %#lx receive queue full\n",
+ ibdev, qp->qpn );
+ return -ENOBUFS;
+ }
- if ( ( rc = ib_mad ( ibdev, hdr, sizeof ( *guid_info ) ) ) != 0 ) {
- DBGC ( ibdev, "IBDEV %p could not get GUID info: %s\n",
- ibdev, strerror ( rc ) );
+ /* Post to hardware */
+ if ( ( rc = ibdev->op->post_recv ( ibdev, qp, iobuf ) ) != 0 ) {
+ DBGC ( ibdev, "IBDEV %p QPN %#lx could not post receive WQE: "
+ "%s\n", ibdev, qp->qpn, strerror ( rc ) );
return rc;
}
+
+ qp->recv.fill++;
return 0;
}
/**
- * Get partition key table
+ * Complete send work queue entry
*
* @v ibdev Infiniband device
- * @v guid_info Partition key table datagram to fill in
- * @ret rc Return status code
+ * @v qp Queue pair
+ * @v iobuf I/O buffer
+ * @v rc Completion status code
*/
-static int ib_get_pkey_table ( struct ib_device *ibdev,
- struct ib_mad_pkey_table *pkey_table ) {
- struct ib_mad_hdr *hdr = &pkey_table->mad_hdr;
- int rc;
-
- /* Construct MAD */
- memset ( pkey_table, 0, sizeof ( *pkey_table ) );
- hdr->base_version = IB_MGMT_BASE_VERSION;
- hdr->mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED;
- hdr->class_version = 1;
- hdr->method = IB_MGMT_METHOD_GET;
- hdr->attr_id = htons ( IB_SMP_ATTR_PKEY_TABLE );
+void ib_complete_send ( struct ib_device *ibdev, struct ib_queue_pair *qp,
+ struct io_buffer *iobuf, int rc ) {
+ qp->send.cq->op->complete_send ( ibdev, qp, iobuf, rc );
+ qp->send.fill--;
+}
- if ( ( rc = ib_mad ( ibdev, hdr, sizeof ( *pkey_table ) ) ) != 0 ) {
- DBGC ( ibdev, "IBDEV %p could not get pkey table: %s\n",
- ibdev, strerror ( rc ) );
- return rc;
- }
- return 0;
+/**
+ * Complete receive work queue entry
+ *
+ * @v ibdev Infiniband device
+ * @v qp Queue pair
+ * @v av Address vector
+ * @v iobuf I/O buffer
+ * @v rc Completion status code
+ */
+void ib_complete_recv ( struct ib_device *ibdev, struct ib_queue_pair *qp,
+ struct ib_address_vector *av,
+ struct io_buffer *iobuf, int rc ) {
+ qp->recv.cq->op->complete_recv ( ibdev, qp, av, iobuf, rc );
+ qp->recv.fill--;
}
/**
- * Get MAD parameters
+ * Attach to multicast group
*
* @v ibdev Infiniband device
+ * @v qp Queue pair
+ * @v gid Multicast GID
* @ret rc Return status code
*/
-static int ib_get_mad_params ( struct ib_device *ibdev ) {
- union {
- /* This union exists just to save stack space */
- struct ib_mad_port_info port_info;
- struct ib_mad_guid_info guid_info;
- struct ib_mad_pkey_table pkey_table;
- } u;
+int ib_mcast_attach ( struct ib_device *ibdev, struct ib_queue_pair *qp,
+ struct ib_gid *gid ) {
+ struct ib_multicast_gid *mgid;
int rc;
- /* Port info gives us the link state, the first half of the
- * port GID and the SM LID.
- */
- if ( ( rc = ib_get_port_info ( ibdev, &u.port_info ) ) != 0 )
- return rc;
- ibdev->link_up = ( ( u.port_info.port_state__link_speed_supported
- & 0xf ) == 4 );
- memcpy ( &ibdev->port_gid.u.bytes[0], u.port_info.gid_prefix, 8 );
- ibdev->sm_lid = ntohs ( u.port_info.mastersm_lid );
+ /* Add to software multicast GID list */
+ mgid = zalloc ( sizeof ( *mgid ) );
+ if ( ! mgid ) {
+ rc = -ENOMEM;
+ goto err_alloc_mgid;
+ }
+ memcpy ( &mgid->gid, gid, sizeof ( mgid->gid ) );
+ list_add ( &mgid->list, &qp->mgids );
- /* GUID info gives us the second half of the port GID */
- if ( ( rc = ib_get_guid_info ( ibdev, &u.guid_info ) ) != 0 )
- return rc;
- memcpy ( &ibdev->port_gid.u.bytes[8], u.guid_info.gid_local, 8 );
+ /* Add to hardware multicast GID list */
+ if ( ( rc = ibdev->op->mcast_attach ( ibdev, qp, gid ) ) != 0 )
+ goto err_dev_mcast_attach;
- /* Get partition key */
- if ( ( rc = ib_get_pkey_table ( ibdev, &u.pkey_table ) ) != 0 )
- return rc;
- ibdev->pkey = ntohs ( u.pkey_table.pkey[0][0] );
+ return 0;
- DBGC ( ibdev, "IBDEV %p port GID is %08lx:%08lx:%08lx:%08lx\n",
- ibdev, htonl ( ibdev->port_gid.u.dwords[0] ),
- htonl ( ibdev->port_gid.u.dwords[1] ),
- htonl ( ibdev->port_gid.u.dwords[2] ),
- htonl ( ibdev->port_gid.u.dwords[3] ) );
+ err_dev_mcast_attach:
+ list_del ( &mgid->list );
+ free ( mgid );
+ err_alloc_mgid:
+ return rc;
+}
- return 0;
+/**
+ * Detach from multicast group
+ *
+ * @v ibdev Infiniband device
+ * @v qp Queue pair
+ * @v gid Multicast GID
+ */
+void ib_mcast_detach ( struct ib_device *ibdev, struct ib_queue_pair *qp,
+ struct ib_gid *gid ) {
+ struct ib_multicast_gid *mgid;
+
+ /* Remove from hardware multicast GID list */
+ ibdev->op->mcast_detach ( ibdev, qp, gid );
+
+ /* Remove from software multicast GID list */
+ list_for_each_entry ( mgid, &qp->mgids, list ) {
+ if ( memcmp ( &mgid->gid, gid, sizeof ( mgid->gid ) ) == 0 ) {
+ list_del ( &mgid->list );
+ free ( mgid );
+ break;
+ }
+ }
}
+
/***************************************************************************
*
* Event queues
@@ -366,14 +464,6 @@ static int ib_get_mad_params ( struct ib_device *ibdev ) {
* @v ibdev Infiniband device
*/
void ib_link_state_changed ( struct ib_device *ibdev ) {
- int rc;
-
- /* Update MAD parameters */
- if ( ( rc = ib_get_mad_params ( ibdev ) ) != 0 ) {
- DBGC ( ibdev, "IBDEV %p could not update MAD parameters: %s\n",
- ibdev, strerror ( rc ) );
- return;
- }
/* Notify IPoIB of link state change */
ipoib_link_state_changed ( ibdev );
@@ -420,6 +510,9 @@ struct ib_device * alloc_ibdev ( size_t priv_size ) {
if ( ibdev ) {
drv_priv = ( ( ( void * ) ibdev ) + sizeof ( *ibdev ) );
ib_set_drvdata ( ibdev, drv_priv );
+ INIT_LIST_HEAD ( &ibdev->qps );
+ ibdev->lid = IB_LID_NONE;
+ ibdev->pkey = IB_PKEY_NONE;
}
return ibdev;
}
@@ -441,10 +534,6 @@ int register_ibdev ( struct ib_device *ibdev ) {
if ( ( rc = ib_open ( ibdev ) ) != 0 )
goto err_open;
- /* Get MAD parameters */
- if ( ( rc = ib_get_mad_params ( ibdev ) ) != 0 )
- goto err_get_mad_params;
-
/* Add IPoIB device */
if ( ( rc = ipoib_probe ( ibdev ) ) != 0 ) {
DBGC ( ibdev, "IBDEV %p could not add IPoIB device: %s\n",
@@ -457,7 +546,6 @@ int register_ibdev ( struct ib_device *ibdev ) {
return 0;
err_ipoib_probe:
- err_get_mad_params:
ib_close ( ibdev );
err_open:
list_del ( &ibdev->list );
diff --git a/gpxe/src/net/ipv4.c b/gpxe/src/net/ipv4.c
index 82a13c33..63dcca28 100644
--- a/gpxe/src/net/ipv4.c
+++ b/gpxe/src/net/ipv4.c
@@ -188,7 +188,7 @@ static struct io_buffer * ipv4_reassemble ( struct io_buffer * iobuf ) {
free_iob ( iobuf );
/** Check if the fragment series is over */
- if ( !iphdr->frags & IP_MASK_MOREFRAGS ) {
+ if ( ! ( iphdr->frags & IP_MASK_MOREFRAGS ) ) {
iobuf = fragbuf->frag_iob;
free_fragbuf ( fragbuf );
return iobuf;
@@ -266,7 +266,6 @@ static uint16_t ipv4_pshdr_chksum ( struct io_buffer *iobuf, uint16_t csum ) {
static int ipv4_ll_addr ( struct in_addr dest, struct in_addr src,
struct net_device *netdev, uint8_t *ll_dest ) {
struct ll_protocol *ll_protocol = netdev->ll_protocol;
- uint8_t *dest_bytes = ( ( uint8_t * ) &dest );
if ( dest.s_addr == INADDR_BROADCAST ) {
/* Broadcast address */
@@ -274,17 +273,7 @@ static int ipv4_ll_addr ( struct in_addr dest, struct in_addr src,
ll_protocol->ll_addr_len );
return 0;
} else if ( IN_MULTICAST ( ntohl ( dest.s_addr ) ) ) {
- /* Special case: IPv4 multicast over Ethernet. This
- * code may need to be generalised once we find out
- * what happens for other link layers.
- */
- ll_dest[0] = 0x01;
- ll_dest[1] = 0x00;
- ll_dest[2] = 0x5e;
- ll_dest[3] = dest_bytes[1] & 0x7f;
- ll_dest[4] = dest_bytes[2];
- ll_dest[5] = dest_bytes[3];
- return 0;
+ return ll_protocol->mc_hash ( AF_INET, &dest, ll_dest );
} else {
/* Unicast address: resolve via ARP */
return arp_resolve ( netdev, &ipv4_protocol, &dest,
diff --git a/gpxe/src/net/netdevice.c b/gpxe/src/net/netdevice.c
index 3721b334..e8587a9d 100644
--- a/gpxe/src/net/netdevice.c
+++ b/gpxe/src/net/netdevice.c
@@ -46,6 +46,45 @@ static struct net_protocol net_protocols_end[0]
struct list_head net_devices = LIST_HEAD_INIT ( net_devices );
/**
+ * Record network device statistic
+ *
+ * @v stats Network device statistics
+ * @v rc Status code
+ */
+static void netdev_record_stat ( struct net_device_stats *stats, int rc ) {
+ struct net_device_error *error;
+ struct net_device_error *least_common_error;
+ unsigned int i;
+
+ /* If this is not an error, just update the good counter */
+ if ( rc == 0 ) {
+ stats->good++;
+ return;
+ }
+
+ /* Update the bad counter */
+ stats->bad++;
+
+ /* Locate the appropriate error record */
+ least_common_error = &stats->errors[0];
+ for ( i = 0 ; i < ( sizeof ( stats->errors ) /
+ sizeof ( stats->errors[0] ) ) ; i++ ) {
+ error = &stats->errors[i];
+ /* Update matching record, if found */
+ if ( error->rc == rc ) {
+ error->count++;
+ return;
+ }
+ if ( error->count < least_common_error->count )
+ least_common_error = error;
+ }
+
+ /* Overwrite the least common error record */
+ least_common_error->rc = rc;
+ least_common_error->count = 1;
+}
+
+/**
* Transmit raw packet via network device
*
* @v netdev Network device
@@ -91,12 +130,11 @@ void netdev_tx_complete_err ( struct net_device *netdev,
struct io_buffer *iobuf, int rc ) {
/* Update statistics counter */
+ netdev_record_stat ( &netdev->tx_stats, rc );
if ( rc == 0 ) {
- netdev->stats.tx_ok++;
DBGC ( netdev, "NETDEV %p transmission %p complete\n",
netdev, iobuf );
} else {
- netdev->stats.tx_err++;
DBGC ( netdev, "NETDEV %p transmission %p failed: %s\n",
netdev, iobuf, strerror ( rc ) );
}
@@ -158,7 +196,7 @@ void netdev_rx ( struct net_device *netdev, struct io_buffer *iobuf ) {
list_add_tail ( &iobuf->list, &netdev->rx_queue );
/* Update statistics counter */
- netdev->stats.rx_ok++;
+ netdev_record_stat ( &netdev->rx_stats, 0 );
}
/**
@@ -183,7 +221,7 @@ void netdev_rx_err ( struct net_device *netdev,
free_iob ( iobuf );
/* Update statistics counter */
- netdev->stats.rx_err++;
+ netdev_record_stat ( &netdev->rx_stats, rc );
}
/**
@@ -268,7 +306,7 @@ struct net_device * alloc_netdev ( size_t priv_size ) {
INIT_LIST_HEAD ( &netdev->rx_queue );
settings_init ( netdev_settings ( netdev ),
&netdev_settings_operations, &netdev->refcnt,
- netdev->name );
+ netdev->name, 0 );
netdev->priv = ( ( ( void * ) netdev ) + sizeof ( *netdev ) );
}
return netdev;
@@ -439,6 +477,7 @@ struct net_device * find_netdev_by_location ( unsigned int bus_type,
*/
int net_tx ( struct io_buffer *iobuf, struct net_device *netdev,
struct net_protocol *net_protocol, const void *ll_dest ) {
+ struct ll_protocol *ll_protocol = netdev->ll_protocol;
int rc;
/* Force a poll on the netdevice to (potentially) clear any
@@ -449,8 +488,8 @@ int net_tx ( struct io_buffer *iobuf, struct net_device *netdev,
netdev_poll ( netdev );
/* Add link-layer header */
- if ( ( rc = netdev->ll_protocol->push ( iobuf, netdev, net_protocol,
- ll_dest ) ) != 0 ) {
+ if ( ( rc = ll_protocol->push ( iobuf, ll_dest, netdev->ll_addr,
+ net_protocol->net_proto ) ) != 0 ) {
free_iob ( iobuf );
return rc;
}
@@ -495,8 +534,9 @@ static void net_step ( struct process *process __unused ) {
struct net_device *netdev;
struct io_buffer *iobuf;
struct ll_protocol *ll_protocol;
- uint16_t net_proto;
+ const void *ll_dest;
const void *ll_source;
+ uint16_t net_proto;
int rc;
/* Poll and process each network device */
@@ -519,9 +559,9 @@ static void net_step ( struct process *process __unused ) {
/* Remove link-layer header */
ll_protocol = netdev->ll_protocol;
- if ( ( rc = ll_protocol->pull ( iobuf, netdev,
- &net_proto,
- &ll_source ) ) != 0 ) {
+ if ( ( rc = ll_protocol->pull ( iobuf, &ll_dest,
+ &ll_source,
+ &net_proto ) ) != 0 ) {
free_iob ( iobuf );
continue;
}
diff --git a/gpxe/src/net/retry.c b/gpxe/src/net/retry.c
index 2a645c97..cd793a7f 100644
--- a/gpxe/src/net/retry.c
+++ b/gpxe/src/net/retry.c
@@ -55,9 +55,10 @@ static LIST_HEAD ( timers );
* be stopped and the timer's callback function will be called.
*/
void start_timer ( struct retry_timer *timer ) {
- if ( ! timer_running ( timer ) )
+ if ( ! timer->running )
list_add ( &timer->list, &timers );
timer->start = currticks();
+ timer->running = 1;
/* 0 means "use default timeout" */
if ( timer->min_timeout == 0 )
@@ -82,6 +83,8 @@ void start_timer ( struct retry_timer *timer ) {
void start_timer_fixed ( struct retry_timer *timer, unsigned long timeout ) {
start_timer ( timer );
timer->timeout = timeout;
+ DBG2 ( "Timer %p expiry time changed to %ld\n",
+ timer, ( timer->start + timer->timeout ) );
}
/**
@@ -97,12 +100,12 @@ void stop_timer ( struct retry_timer *timer ) {
unsigned long runtime;
/* If timer was already stopped, do nothing */
- if ( ! timer_running ( timer ) )
+ if ( ! timer->running )
return;
list_del ( &timer->list );
runtime = ( now - timer->start );
- timer->start = 0;
+ timer->running = 0;
DBG2 ( "Timer %p stopped at time %ld (ran for %ld)\n",
timer, now, runtime );
@@ -144,8 +147,9 @@ static void timer_expired ( struct retry_timer *timer ) {
/* Stop timer without performing RTT calculations */
DBG2 ( "Timer %p stopped at time %ld on expiry\n",
timer, currticks() );
+ assert ( timer->running );
list_del ( &timer->list );
- timer->start = 0;
+ timer->running = 0;
timer->count++;
/* Back off the timeout value */
diff --git a/gpxe/src/net/tcp/ftp.c b/gpxe/src/net/tcp/ftp.c
index 3b88f7b6..82dc19ca 100644
--- a/gpxe/src/net/tcp/ftp.c
+++ b/gpxe/src/net/tcp/ftp.c
@@ -109,23 +109,39 @@ static void ftp_done ( struct ftp_request *ftp, int rc ) {
*
*/
+/** An FTP control channel string */
+struct ftp_control_string {
+ /** Literal portion */
+ const char *literal;
+ /** Variable portion
+ *
+ * @v ftp FTP request
+ * @ret string Variable portion of string
+ */
+ const char * ( *variable ) ( struct ftp_request *ftp );
+};
+
/**
- * FTP control channel strings
+ * Retrieve FTP pathname
*
- * These are used as printf() format strings. Since only one of them
- * (RETR) takes an argument, we always supply that argument to the
- * snprintf() call.
+ * @v ftp FTP request
+ * @ret path FTP pathname
*/
-static const char * ftp_strings[] = {
- [FTP_CONNECT] = NULL,
- [FTP_USER] = "USER anonymous\r\n",
- [FTP_PASS] = "PASS etherboot@etherboot.org\r\n",
- [FTP_TYPE] = "TYPE I\r\n",
- [FTP_PASV] = "PASV\r\n",
- [FTP_RETR] = "RETR %s\r\n",
- [FTP_WAIT] = NULL,
- [FTP_QUIT] = "QUIT\r\n",
- [FTP_DONE] = NULL,
+static const char * ftp_uri_path ( struct ftp_request *ftp ) {
+ return ftp->uri->path;
+}
+
+/** FTP control channel strings */
+static struct ftp_control_string ftp_strings[] = {
+ [FTP_CONNECT] = { NULL, NULL },
+ [FTP_USER] = { "USER anonymous", NULL },
+ [FTP_PASS] = { "PASS etherboot@etherboot.org", NULL },
+ [FTP_TYPE] = { "TYPE I", NULL },
+ [FTP_PASV] = { "PASV", NULL },
+ [FTP_RETR] = { "RETR ", ftp_uri_path },
+ [FTP_WAIT] = { NULL, NULL },
+ [FTP_QUIT] = { "QUIT", NULL },
+ [FTP_DONE] = { NULL, NULL },
};
/**
@@ -178,18 +194,23 @@ static void ftp_parse_value ( char **text, uint8_t *value, size_t len ) {
*
*/
static void ftp_next_state ( struct ftp_request *ftp ) {
+ struct ftp_control_string *ftp_string;
+ const char *literal;
+ const char *variable;
/* Move to next state */
if ( ftp->state < FTP_DONE )
ftp->state++;
/* Send control string if needed */
- if ( ftp_strings[ftp->state] != NULL ) {
- DBGC ( ftp, "FTP %p sending ", ftp );
- DBGC ( ftp, ftp_strings[ftp->state], ftp->uri->path );
- xfer_printf ( &ftp->control, ftp_strings[ftp->state],
- ftp->uri->path );
- }
+ ftp_string = &ftp_strings[ftp->state];
+ literal = ftp_string->literal;
+ variable = ( ftp_string->variable ?
+ ftp_string->variable ( ftp ) : "" );
+ if ( literal ) {
+ DBGC ( ftp, "FTP %p sending %s%s\n", ftp, literal, variable );
+ xfer_printf ( &ftp->control, "%s%s\r\n", literal, variable );
+ }
}
/**
diff --git a/gpxe/src/net/tls.c b/gpxe/src/net/tls.c
index 834686fb..fa4b58d4 100644
--- a/gpxe/src/net/tls.c
+++ b/gpxe/src/net/tls.c
@@ -270,16 +270,16 @@ static void tls_generate_master_secret ( struct tls_session *tls ) {
DBGC_HD ( tls, &tls->pre_master_secret,
sizeof ( tls->pre_master_secret ) );
DBGC ( tls, "TLS %p client random bytes:\n", tls );
- DBGC_HD ( tls, &tls->client_random, sizeof ( tls->server_random ) );
+ DBGC_HD ( tls, &tls->client_random, sizeof ( tls->client_random ) );
DBGC ( tls, "TLS %p server random bytes:\n", tls );
DBGC_HD ( tls, &tls->server_random, sizeof ( tls->server_random ) );
- tls_prf_label ( tls, tls->pre_master_secret,
+ tls_prf_label ( tls, &tls->pre_master_secret,
sizeof ( tls->pre_master_secret ),
- tls->master_secret, sizeof ( tls->master_secret ),
+ &tls->master_secret, sizeof ( tls->master_secret ),
"master secret",
- tls->client_random, sizeof ( tls->client_random ),
- tls->server_random, sizeof ( tls->server_random ) );
+ &tls->client_random, sizeof ( tls->client_random ),
+ &tls->server_random, sizeof ( tls->server_random ) );
DBGC ( tls, "TLS %p generated master secret:\n", tls );
DBGC_HD ( tls, &tls->master_secret, sizeof ( tls->master_secret ) );
@@ -304,10 +304,10 @@ static int tls_generate_keys ( struct tls_session *tls ) {
int rc;
/* Generate key block */
- tls_prf_label ( tls, tls->master_secret, sizeof ( tls->master_secret ),
+ tls_prf_label ( tls, &tls->master_secret, sizeof ( tls->master_secret ),
key_block, sizeof ( key_block ), "key expansion",
- tls->server_random, sizeof ( tls->server_random ),
- tls->client_random, sizeof ( tls->client_random ) );
+ &tls->server_random, sizeof ( tls->server_random ),
+ &tls->client_random, sizeof ( tls->client_random ) );
/* Split key block into portions */
key = key_block;
@@ -604,7 +604,7 @@ static int tls_send_client_hello ( struct tls_session *tls ) {
htonl ( sizeof ( hello ) -
sizeof ( hello.type_length ) ) );
hello.version = htons ( TLS_VERSION_TLS_1_0 );
- memcpy ( &hello.random, tls->client_random, sizeof ( hello.random ) );
+ memcpy ( &hello.random, &tls->client_random, sizeof ( hello.random ) );
hello.cipher_suite_len = htons ( sizeof ( hello.cipher_suites ) );
hello.cipher_suites[0] = htons ( TLS_RSA_WITH_AES_128_CBC_SHA );
hello.cipher_suites[1] = htons ( TLS_RSA_WITH_AES_256_CBC_SHA );
@@ -643,7 +643,7 @@ static int tls_send_client_key_exchange ( struct tls_session *tls ) {
sizeof ( tls->pre_master_secret ) );
DBGC_HD ( tls, tls->rsa_mod, tls->rsa_mod_len );
DBGC_HD ( tls, tls->rsa_pub_exp, tls->rsa_pub_exp_len );
- RSA_encrypt ( rsa_ctx, tls->pre_master_secret,
+ RSA_encrypt ( rsa_ctx, ( const uint8_t * ) &tls->pre_master_secret,
sizeof ( tls->pre_master_secret ),
key_xchg.encrypted_pre_master_secret, 0 );
DBGC ( tls, "RSA encrypt done. Ciphertext:\n" );
@@ -685,7 +685,7 @@ static int tls_send_finished ( struct tls_session *tls ) {
htonl ( sizeof ( finished ) -
sizeof ( finished.type_length ) ) );
tls_verify_handshake ( tls, digest );
- tls_prf_label ( tls, tls->master_secret, sizeof ( tls->master_secret ),
+ tls_prf_label ( tls, &tls->master_secret, sizeof ( tls->master_secret ),
finished.verify_data, sizeof ( finished.verify_data ),
"client finished", digest, sizeof ( digest ) );
@@ -802,7 +802,7 @@ static int tls_new_server_hello ( struct tls_session *tls,
}
/* Copy out server random bytes */
- memcpy ( tls->server_random, hello_a->random,
+ memcpy ( &tls->server_random, &hello_a->random,
sizeof ( tls->server_random ) );
/* Select cipher suite */
@@ -1710,13 +1710,12 @@ int add_tls ( struct xfer_interface *xfer, struct xfer_interface **next ) {
tls_clear_cipher ( tls, &tls->tx_cipherspec_pending );
tls_clear_cipher ( tls, &tls->rx_cipherspec );
tls_clear_cipher ( tls, &tls->rx_cipherspec_pending );
- *( ( uint32_t * ) tls->client_random ) = 0; /* GMT Unix time */
- tls_generate_random ( ( tls->client_random + 4 ),
- ( sizeof ( tls->client_random ) - 4 ) );
- *( ( uint16_t * ) tls->pre_master_secret )
- = htons ( TLS_VERSION_TLS_1_0 );
- tls_generate_random ( ( tls->pre_master_secret + 2 ),
- ( sizeof ( tls->pre_master_secret ) - 2 ) );
+ tls->client_random.gmt_unix_time = 0;
+ tls_generate_random ( &tls->client_random.random,
+ ( sizeof ( tls->client_random.random ) ) );
+ tls->pre_master_secret.version = htons ( TLS_VERSION_TLS_1_0 );
+ tls_generate_random ( &tls->pre_master_secret.random,
+ ( sizeof ( tls->pre_master_secret.random ) ) );
digest_init ( &md5_algorithm, tls->handshake_md5_ctx );
digest_init ( &sha1_algorithm, tls->handshake_sha1_ctx );
tls->tx_state = TLS_TX_CLIENT_HELLO;
diff --git a/gpxe/src/net/udp/dhcp.c b/gpxe/src/net/udp/dhcp.c
index ab751cd5..21347832 100644
--- a/gpxe/src/net/udp/dhcp.c
+++ b/gpxe/src/net/udp/dhcp.c
@@ -256,7 +256,7 @@ static struct dhcp_settings * dhcpset_create ( const struct dhcphdr *dhcphdr,
dhcppkt_init ( &dhcpset->dhcppkt, data, len );
settings_init ( &dhcpset->settings,
&dhcpset_settings_operations, &dhcpset->refcnt,
- DHCP_SETTINGS_NAME );
+ DHCP_SETTINGS_NAME, 0 );
}
return dhcpset;
}
diff --git a/gpxe/src/net/udp/tftp.c b/gpxe/src/net/udp/tftp.c
index 8fdb3714..b262b108 100644
--- a/gpxe/src/net/udp/tftp.c
+++ b/gpxe/src/net/udp/tftp.c
@@ -45,6 +45,15 @@
FEATURE ( FEATURE_PROTOCOL, "TFTP", DHCP_EB_FEATURE_TFTP, 1 );
+/* TFTP-specific error codes */
+#define ETFTP_INVALID_BLKSIZE EUNIQ_01
+#define ETFTP_INVALID_TSIZE EUNIQ_02
+#define ETFTP_MC_NO_PORT EUNIQ_03
+#define ETFTP_MC_NO_MC EUNIQ_04
+#define ETFTP_MC_INVALID_MC EUNIQ_05
+#define ETFTP_MC_INVALID_IP EUNIQ_06
+#define ETFTP_MC_INVALID_PORT EUNIQ_07
+
/**
* A TFTP request
*
@@ -504,7 +513,7 @@ static int tftp_process_blksize ( struct tftp_request *tftp,
if ( *end ) {
DBGC ( tftp, "TFTP %p got invalid blksize \"%s\"\n",
tftp, value );
- return -EINVAL;
+ return -( EINVAL | ETFTP_INVALID_BLKSIZE );
}
DBGC ( tftp, "TFTP %p blksize=%d\n", tftp, tftp->blksize );
@@ -526,7 +535,7 @@ static int tftp_process_tsize ( struct tftp_request *tftp,
if ( *end ) {
DBGC ( tftp, "TFTP %p got invalid tsize \"%s\"\n",
tftp, value );
- return -EINVAL;
+ return -( EINVAL | ETFTP_INVALID_TSIZE );
}
DBGC ( tftp, "TFTP %p tsize=%ld\n", tftp, tftp->tsize );
@@ -560,13 +569,13 @@ static int tftp_process_multicast ( struct tftp_request *tftp,
port = strchr ( addr, ',' );
if ( ! port ) {
DBGC ( tftp, "TFTP %p multicast missing port,mc\n", tftp );
- return -EINVAL;
+ return -( EINVAL | ETFTP_MC_NO_PORT );
}
*(port++) = '\0';
mc = strchr ( port, ',' );
if ( ! mc ) {
DBGC ( tftp, "TFTP %p multicast missing mc\n", tftp );
- return -EINVAL;
+ return -( EINVAL | ETFTP_MC_NO_MC );
}
*(mc++) = '\0';
@@ -575,7 +584,7 @@ static int tftp_process_multicast ( struct tftp_request *tftp,
tftp->flags &= ~TFTP_FL_SEND_ACK;
if ( *mc_end ) {
DBGC ( tftp, "TFTP %p multicast invalid mc %s\n", tftp, mc );
- return -EINVAL;
+ return -( EINVAL | ETFTP_MC_INVALID_MC );
}
DBGC ( tftp, "TFTP %p is%s the master client\n",
tftp, ( ( tftp->flags & TFTP_FL_SEND_ACK ) ? "" : " not" ) );
@@ -584,7 +593,7 @@ static int tftp_process_multicast ( struct tftp_request *tftp,
if ( inet_aton ( addr, &socket.sin.sin_addr ) == 0 ) {
DBGC ( tftp, "TFTP %p multicast invalid IP address "
"%s\n", tftp, addr );
- return -EINVAL;
+ return -( EINVAL | ETFTP_MC_INVALID_IP );
}
DBGC ( tftp, "TFTP %p multicast IP address %s\n",
tftp, inet_ntoa ( socket.sin.sin_addr ) );
@@ -592,7 +601,7 @@ static int tftp_process_multicast ( struct tftp_request *tftp,
if ( *port_end ) {
DBGC ( tftp, "TFTP %p multicast invalid port %s\n",
tftp, port );
- return -EINVAL;
+ return -( EINVAL | ETFTP_MC_INVALID_PORT );
}
DBGC ( tftp, "TFTP %p multicast port %d\n",
tftp, ntohs ( socket.sin.sin_port ) );
diff --git a/gpxe/src/tests/gdbstub_test.gdb b/gpxe/src/tests/gdbstub_test.gdb
index 52aa693f..52aa693f 100644..100755
--- a/gpxe/src/tests/gdbstub_test.gdb
+++ b/gpxe/src/tests/gdbstub_test.gdb
diff --git a/gpxe/src/usr/aoeboot.c b/gpxe/src/usr/aoeboot.c
index f0e481bd..e977b10f 100644
--- a/gpxe/src/usr/aoeboot.c
+++ b/gpxe/src/usr/aoeboot.c
@@ -6,9 +6,9 @@
#include <gpxe/ata.h>
#include <gpxe/netdevice.h>
#include <gpxe/settings.h>
+#include <gpxe/sanboot.h>
#include <gpxe/abft.h>
#include <int13.h>
-#include <usr/aoeboot.h>
/**
* Guess boot network device
@@ -16,17 +16,18 @@
* @ret netdev Boot network device
*/
static struct net_device * guess_boot_netdev ( void ) {
- struct net_device *boot_netdev;
+ struct net_device *netdev;
/* Just use the first network device */
- for_each_netdev ( boot_netdev ) {
- return boot_netdev;
+ for_each_netdev ( netdev ) {
+ if ( netdev->state & NETDEV_OPEN )
+ return netdev;
}
return NULL;
}
-int aoeboot ( const char *root_path ) {
+static int aoeboot ( const char *root_path ) {
struct ata_device ata;
struct int13_drive drive;
int rc;
@@ -71,3 +72,8 @@ int aoeboot ( const char *root_path ) {
error_attach:
return rc;
}
+
+struct sanboot_protocol aoe_sanboot_protocol __sanboot_protocol = {
+ .prefix = "aoe:",
+ .boot = aoeboot,
+};
diff --git a/gpxe/src/usr/autoboot.c b/gpxe/src/usr/autoboot.c
index 326292b4..f5f7f7d1 100644
--- a/gpxe/src/usr/autoboot.c
+++ b/gpxe/src/usr/autoboot.c
@@ -24,13 +24,12 @@
#include <gpxe/settings.h>
#include <gpxe/image.h>
#include <gpxe/embedded.h>
+#include <gpxe/sanboot.h>
#include <gpxe/uri.h>
#include <usr/ifmgmt.h>
#include <usr/route.h>
#include <usr/dhcpmgmt.h>
#include <usr/imgmgmt.h>
-#include <usr/iscsiboot.h>
-#include <usr/aoeboot.h>
#include <usr/autoboot.h>
/** @file
@@ -45,6 +44,12 @@
/** Shutdown flags for exit */
int shutdown_exit_flags = 0;
+/* SAN boot protocols */
+static struct sanboot_protocol sanboot_protocols[0] \
+ __table_start ( struct sanboot_protocol, sanboot_protocols );
+static struct sanboot_protocol sanboot_protocols_end[0] \
+ __table_end ( struct sanboot_protocol, sanboot_protocols );
+
/**
* Identify the boot network device
*
@@ -141,12 +146,15 @@ static int boot_next_server_and_filename ( struct in_addr next_server,
* @ret rc Return status code
*/
int boot_root_path ( const char *root_path ) {
+ struct sanboot_protocol *sanboot;
/* Quick hack */
- if ( strncmp ( root_path, "iscsi:", 6 ) == 0 ) {
- return iscsiboot ( root_path );
- } else if ( strncmp ( root_path, "aoe:", 4 ) == 0 ) {
- return aoeboot ( root_path );
+ for ( sanboot = sanboot_protocols ;
+ sanboot < sanboot_protocols_end ; sanboot++ ) {
+ if ( strncmp ( root_path, sanboot->prefix,
+ strlen ( sanboot->prefix ) ) == 0 ) {
+ return sanboot->boot ( root_path );
+ }
}
return -ENOTSUP;
diff --git a/gpxe/src/usr/ifmgmt.c b/gpxe/src/usr/ifmgmt.c
index 9c88ab53..72d86137 100644
--- a/gpxe/src/usr/ifmgmt.c
+++ b/gpxe/src/usr/ifmgmt.c
@@ -59,6 +59,25 @@ void ifclose ( struct net_device *netdev ) {
}
/**
+ * Print network device error breakdown
+ *
+ * @v stats Network device statistics
+ * @v prefix Message prefix
+ */
+static void ifstat_errors ( struct net_device_stats *stats,
+ const char *prefix ) {
+ unsigned int i;
+
+ for ( i = 0 ; i < ( sizeof ( stats->errors ) /
+ sizeof ( stats->errors[0] ) ) ; i++ ) {
+ if ( stats->errors[i].count )
+ printf ( " [%s: %d x \"%s\"]\n", prefix,
+ stats->errors[i].count,
+ strerror ( stats->errors[i].rc ) );
+ }
+}
+
+/**
* Print status of network device
*
* @v netdev Network device
@@ -69,8 +88,10 @@ void ifstat ( struct net_device *netdev ) {
netdev->name, netdev_hwaddr ( netdev ), netdev->dev->name,
( ( netdev->state & NETDEV_OPEN ) ? "open" : "closed" ),
( netdev_link_ok ( netdev ) ? "up" : "down" ),
- netdev->stats.tx_ok, netdev->stats.tx_err,
- netdev->stats.rx_ok, netdev->stats.rx_err );
+ netdev->tx_stats.good, netdev->tx_stats.bad,
+ netdev->rx_stats.good, netdev->rx_stats.bad );
+ ifstat_errors ( &netdev->tx_stats, "TXE" );
+ ifstat_errors ( &netdev->rx_stats, "RXE" );
}
/**
diff --git a/gpxe/src/usr/iscsiboot.c b/gpxe/src/usr/iscsiboot.c
index 84d77c45..cdf7790b 100644
--- a/gpxe/src/usr/iscsiboot.c
+++ b/gpxe/src/usr/iscsiboot.c
@@ -9,9 +9,9 @@
#include <gpxe/netdevice.h>
#include <gpxe/ibft.h>
#include <gpxe/init.h>
+#include <gpxe/sanboot.h>
#include <int13.h>
#include <usr/autoboot.h>
-#include <usr/iscsiboot.h>
struct setting keep_san_setting __setting = {
.name = "keep-san",
@@ -26,17 +26,18 @@ struct setting keep_san_setting __setting = {
* @ret netdev Boot network device
*/
static struct net_device * guess_boot_netdev ( void ) {
- struct net_device *boot_netdev;
+ struct net_device *netdev;
/* Just use the first network device */
- for_each_netdev ( boot_netdev ) {
- return boot_netdev;
+ for_each_netdev ( netdev ) {
+ if ( netdev->state & NETDEV_OPEN )
+ return netdev;
}
return NULL;
}
-int iscsiboot ( const char *root_path ) {
+static int iscsiboot ( const char *root_path ) {
struct scsi_device *scsi;
struct int13_drive *drive;
int keep_san;
@@ -100,3 +101,8 @@ int iscsiboot ( const char *root_path ) {
err_alloc_scsi:
return rc;
}
+
+struct sanboot_protocol iscsi_sanboot_protocol __sanboot_protocol = {
+ .prefix = "iscsi:",
+ .boot = iscsiboot,
+};
diff --git a/gpxe/src/util/.gitignore b/gpxe/src/util/.gitignore
index 98adc2df..7f9d7557 100644
--- a/gpxe/src/util/.gitignore
+++ b/gpxe/src/util/.gitignore
@@ -2,3 +2,4 @@ nrv2b
zbin
hijack
prototester
+efilink
diff --git a/gpxe/src/util/efilink.c b/gpxe/src/util/efilink.c
new file mode 100644
index 00000000..e21f4a90
--- /dev/null
+++ b/gpxe/src/util/efilink.c
@@ -0,0 +1,507 @@
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <bfd.h>
+
+struct bfd_file {
+ bfd *bfd;
+ asymbol **symtab;
+ long symcount;
+};
+
+struct pe_relocs {
+ struct pe_relocs *next;
+ unsigned long start_rva;
+ unsigned int used_relocs;
+ unsigned int total_relocs;
+ uint16_t *relocs;
+};
+
+/**
+ * Allocate memory
+ *
+ * @v len Length of memory to allocate
+ * @ret ptr Pointer to allocated memory
+ */
+static void * xmalloc ( size_t len ) {
+ void *ptr;
+
+ ptr = malloc ( len );
+ if ( ! ptr ) {
+ fprintf ( stderr, "Could not allocate %zd bytes\n", len );
+ exit ( 1 );
+ }
+
+ return ptr;
+}
+
+/**
+ * Generate entry in PE relocation table
+ *
+ * @v pe_reltab PE relocation table
+ * @v rva RVA
+ * @v size Size of relocation entry
+ */
+static void generate_pe_reloc ( struct pe_relocs **pe_reltab,
+ unsigned long rva, size_t size ) {
+ unsigned long start_rva;
+ uint16_t reloc;
+ struct pe_relocs *pe_rel;
+ uint16_t *relocs;
+
+ /* Construct */
+ start_rva = ( rva & ~0xfff );
+ reloc = ( rva & 0xfff );
+ switch ( size ) {
+ case 4:
+ reloc |= 0x3000;
+ break;
+ case 2:
+ reloc |= 0x2000;
+ break;
+ default:
+ fprintf ( stderr, "Unsupported relocation size %zd\n", size );
+ exit ( 1 );
+ }
+
+ /* Locate or create PE relocation table */
+ for ( pe_rel = *pe_reltab ; pe_rel ; pe_rel = pe_rel->next ) {
+ if ( pe_rel->start_rva == start_rva )
+ break;
+ }
+ if ( ! pe_rel ) {
+ pe_rel = xmalloc ( sizeof ( *pe_rel ) );
+ memset ( pe_rel, 0, sizeof ( *pe_rel ) );
+ pe_rel->next = *pe_reltab;
+ *pe_reltab = pe_rel;
+ pe_rel->start_rva = start_rva;
+ }
+
+ /* Expand relocation list if necessary */
+ if ( pe_rel->used_relocs < pe_rel->total_relocs ) {
+ relocs = pe_rel->relocs;
+ } else {
+ pe_rel->total_relocs = ( pe_rel->total_relocs ?
+ ( pe_rel->total_relocs * 2 ) : 256 );
+ relocs = xmalloc ( pe_rel->total_relocs *
+ sizeof ( pe_rel->relocs[0] ) );
+ memset ( relocs, 0,
+ pe_rel->total_relocs * sizeof ( pe_rel->relocs[0] ) );
+ memcpy ( relocs, pe_rel->relocs,
+ pe_rel->used_relocs * sizeof ( pe_rel->relocs[0] ) );
+ free ( pe_rel->relocs );
+ pe_rel->relocs = relocs;
+ }
+
+ /* Store relocation */
+ pe_rel->relocs[ pe_rel->used_relocs++ ] = reloc;
+}
+
+/**
+ * Calculate size of binary PE relocation table
+ *
+ * @v pe_reltab PE relocation table
+ * @v buffer Buffer to contain binary table, or NULL
+ * @ret size Size of binary table
+ */
+static size_t output_pe_reltab ( struct pe_relocs *pe_reltab,
+ void *buffer ) {
+ struct pe_relocs *pe_rel;
+ unsigned int num_relocs;
+ size_t size;
+ size_t total_size = 0;
+
+ for ( pe_rel = pe_reltab ; pe_rel ; pe_rel = pe_rel->next ) {
+ num_relocs = ( ( pe_rel->used_relocs + 1 ) & ~1 );
+ size = ( sizeof ( uint32_t ) /* VirtualAddress */ +
+ sizeof ( uint32_t ) /* SizeOfBlock */ +
+ ( num_relocs * sizeof ( uint16_t ) ) );
+ if ( buffer ) {
+ *( (uint32_t *) ( buffer + total_size + 0 ) )
+ = pe_rel->start_rva;
+ *( (uint32_t *) ( buffer + total_size + 4 ) ) = size;
+ memcpy ( ( buffer + total_size + 8 ), pe_rel->relocs,
+ ( num_relocs * sizeof ( uint16_t ) ) );
+ }
+ total_size += size;
+ }
+
+ return total_size;
+}
+
+/**
+ * Read symbol table
+ *
+ * @v bfd BFD file
+ */
+static void read_symtab ( struct bfd_file *bfd ) {
+ long symtab_size;
+
+ /* Get symbol table size */
+ symtab_size = bfd_get_symtab_upper_bound ( bfd->bfd );
+ if ( symtab_size < 0 ) {
+ bfd_perror ( "Could not get symbol table upper bound" );
+ exit ( 1 );
+ }
+
+ /* Allocate and read symbol table */
+ bfd->symtab = xmalloc ( symtab_size );
+ bfd->symcount = bfd_canonicalize_symtab ( bfd->bfd, bfd->symtab );
+ if ( bfd->symcount < 0 ) {
+ bfd_perror ( "Cannot read symbol table" );
+ exit ( 1 );
+ }
+}
+
+/**
+ * Read relocation table
+ *
+ * @v bfd BFD file
+ * @v section Section
+ * @v symtab Symbol table
+ * @ret reltab Relocation table
+ */
+static arelent ** read_reltab ( struct bfd_file *bfd, asection *section ) {
+ long reltab_size;
+ arelent **reltab;
+ long numrels;
+
+ /* Get relocation table size */
+ reltab_size = bfd_get_reloc_upper_bound ( bfd->bfd, section );
+ if ( reltab_size < 0 ) {
+ bfd_perror ( "Could not get relocation table upper bound" );
+ exit ( 1 );
+ }
+
+ /* Allocate and read relocation table */
+ reltab = xmalloc ( reltab_size );
+ numrels = bfd_canonicalize_reloc ( bfd->bfd, section, reltab,
+ bfd->symtab );
+ if ( numrels < 0 ) {
+ bfd_perror ( "Cannot read relocation table" );
+ exit ( 1 );
+ }
+
+ return reltab;
+}
+
+
+/**
+ * Open input BFD file
+ *
+ * @v filename File name
+ * @ret ibfd BFD file
+ */
+static struct bfd_file * open_input_bfd ( const char *filename ) {
+ struct bfd_file *ibfd;
+
+ /* Create BFD file */
+ ibfd = xmalloc ( sizeof ( *ibfd ) );
+ memset ( ibfd, 0, sizeof ( *ibfd ) );
+
+ /* Open the file */
+ ibfd->bfd = bfd_openr ( filename, NULL );
+ if ( ! ibfd->bfd ) {
+ fprintf ( stderr, "Cannot open %s: ", filename );
+ bfd_perror ( NULL );
+ exit ( 1 );
+ }
+
+ /* The call to bfd_check_format() must be present, otherwise
+ * we get a segfault from later BFD calls.
+ */
+ if ( bfd_check_format ( ibfd->bfd, bfd_object ) < 0 ) {
+ fprintf ( stderr, "%s is not an object file\n", filename );
+ exit ( 1 );
+ }
+
+ /* Read symbols and relocation entries */
+ read_symtab ( ibfd );
+
+ return ibfd;
+}
+
+/**
+ * Open output BFD file
+ *
+ * @v filename File name
+ * @v ibfd Input BFD file
+ * @ret obfd BFD file
+ */
+static struct bfd_file * open_output_bfd ( const char *filename,
+ struct bfd_file *ibfd ) {
+ struct bfd_file *obfd;
+ asection *isection;
+ asection *osection;
+
+ /*
+ * Most of this code is based on what objcopy.c does.
+ *
+ */
+
+ /* Create BFD file */
+ obfd = xmalloc ( sizeof ( *obfd ) );
+ memset ( obfd, 0, sizeof ( *obfd ) );
+
+ /* Open the file */
+ obfd->bfd = bfd_openw ( filename, ibfd->bfd->xvec->name );
+ if ( ! obfd->bfd ) {
+ fprintf ( stderr, "Cannot open %s: ", filename );
+ bfd_perror ( NULL );
+ exit ( 1 );
+ }
+
+ /* Copy per-file data */
+ if ( ! bfd_set_arch_mach ( obfd->bfd, bfd_get_arch ( ibfd->bfd ),
+ bfd_get_mach ( ibfd->bfd ) ) ) {
+ bfd_perror ( "Cannot copy architecture" );
+ exit ( 1 );
+ }
+ if ( ! bfd_set_format ( obfd->bfd, bfd_get_format ( ibfd->bfd ) ) ) {
+ bfd_perror ( "Cannot copy format" );
+ exit ( 1 );
+ }
+ if ( ! bfd_copy_private_header_data ( ibfd->bfd, obfd->bfd ) ) {
+ bfd_perror ( "Cannot copy private header data" );
+ exit ( 1 );
+ }
+
+ /* Create sections */
+ for ( isection = ibfd->bfd->sections ; isection ;
+ isection = isection->next ) {
+ osection = bfd_make_section_anyway ( obfd->bfd,
+ isection->name );
+ if ( ! osection ) {
+ bfd_perror ( "Cannot create section" );
+ exit ( 1 );
+ }
+ if ( ! bfd_set_section_flags ( obfd->bfd, osection,
+ isection->flags ) ) {
+ bfd_perror ( "Cannot copy section flags" );
+ exit ( 1 );
+ }
+ if ( ! bfd_set_section_size ( obfd->bfd, osection,
+ bfd_section_size ( ibfd->bfd, isection ) ) ) {
+ bfd_perror ( "Cannot copy section size" );
+ exit ( 1 );
+ }
+ if ( ! bfd_set_section_vma ( obfd->bfd, osection,
+ bfd_section_vma ( ibfd->bfd, isection ) ) ) {
+ bfd_perror ( "Cannot copy section VMA" );
+ exit ( 1 );
+ }
+ osection->lma = bfd_section_lma ( ibfd->bfd, isection );
+ if ( ! bfd_set_section_alignment ( obfd->bfd, osection,
+ bfd_section_alignment ( ibfd->bfd, isection ) ) ) {
+ bfd_perror ( "Cannot copy section alignment" );
+ exit ( 1 );
+ }
+ osection->entsize = isection->entsize;
+ isection->output_section = osection;
+ isection->output_offset = 0;
+ if ( ! bfd_copy_private_section_data ( ibfd->bfd, isection,
+ obfd->bfd, osection ) ){
+ bfd_perror ( "Cannot copy section private data" );
+ exit ( 1 );
+ }
+ }
+
+ /* Copy symbol table */
+ bfd_set_symtab ( obfd->bfd, ibfd->symtab, ibfd->symcount );
+ obfd->symtab = ibfd->symtab;
+
+ return obfd;
+}
+
+/**
+ * Copy section from input BFD file to output BFD file
+ *
+ * @v obfd Output BFD file
+ * @v ibfd Input BFD file
+ * @v section Section
+ */
+static void copy_bfd_section ( struct bfd_file *obfd, struct bfd_file *ibfd,
+ asection *isection ) {
+ size_t size;
+ void *buf;
+ arelent **reltab;
+ arelent **rel;
+ char *errmsg;
+
+ /* Read in original section */
+ size = bfd_section_size ( ibfd->bfd, isection );
+ if ( ! size )
+ return;
+ buf = xmalloc ( size );
+ if ( ( ! bfd_get_section_contents ( ibfd->bfd, isection,
+ buf, 0, size ) ) ) {
+ fprintf ( stderr, "Cannot read section %s: ", isection->name );
+ bfd_perror ( NULL );
+ exit ( 1 );
+ }
+
+ /* Perform relocations. We do this here, rather than letting
+ * ld do it for us when creating the input ELF file, so that
+ * we can change symbol values as a result of having created
+ * the .reloc section.
+ */
+ reltab = read_reltab ( ibfd, isection );
+ for ( rel = reltab ; *rel ; rel++ ) {
+ bfd_perform_relocation ( ibfd->bfd, *rel, buf, isection,
+ NULL, &errmsg );
+ }
+ free ( reltab );
+
+ /* Write out modified section */
+ if ( ( ! bfd_set_section_contents ( obfd->bfd,
+ isection->output_section,
+ buf, 0, size ) ) ) {
+ fprintf ( stderr, "Cannot write section %s: ",
+ isection->output_section->name );
+ bfd_perror ( NULL );
+ exit ( 1 );
+ }
+
+ free ( buf );
+}
+
+/**
+ * Process relocation record
+ *
+ * @v section Section
+ * @v rel Relocation entry
+ * @v pe_reltab PE relocation table to fill in
+ */
+static void process_reloc ( asection *section, arelent *rel,
+ struct pe_relocs **pe_reltab ) {
+ reloc_howto_type *howto = rel->howto;
+ asymbol *sym = *(rel->sym_ptr_ptr);
+ unsigned long offset = ( section->lma + rel->address );
+
+ if ( bfd_is_abs_section ( sym->section ) ) {
+ /* Skip absolute symbols; the symbol value won't
+ * change when the object is loaded.
+ */
+ } else if ( strcmp ( howto->name, "R_386_32" ) == 0 ) {
+ /* Generate a 4-byte PE relocation */
+ generate_pe_reloc ( pe_reltab, offset, 4 );
+ } else if ( strcmp ( howto->name, "R_386_16" ) == 0 ) {
+ /* Generate a 2-byte PE relocation */
+ generate_pe_reloc ( pe_reltab, offset, 2 );
+ } else if ( strcmp ( howto->name, "R_386_PC32" ) == 0 ) {
+ /* Skip PC-relative relocations; all relative offsets
+ * remain unaltered when the object is loaded.
+ */
+ } else {
+ fprintf ( stderr, "Unrecognised relocation type %s\n",
+ howto->name );
+ exit ( 1 );
+ }
+}
+
+/**
+ * Create .reloc section
+ *
+ * obfd Output BFD file
+ * section .reloc section in output file
+ * pe_reltab PE relocation table
+ */
+static void create_reloc_section ( struct bfd_file *obfd, asection *section,
+ struct pe_relocs *pe_reltab ) {
+ size_t raw_size;
+ size_t size;
+ size_t old_size;
+ void *buf;
+ asymbol **sym;
+
+ /* Build binary PE relocation table */
+ raw_size = output_pe_reltab ( pe_reltab, NULL );
+ size = ( ( raw_size + 31 ) & ~31 );
+ buf = xmalloc ( size );
+ memset ( buf, 0, size );
+ output_pe_reltab ( pe_reltab, buf );
+
+ /* Write .reloc section */
+ old_size = bfd_section_size ( obfd->bfd, section );
+ if ( ! bfd_set_section_size ( obfd->bfd, section, size ) ) {
+ bfd_perror ( "Cannot resize .reloc section" );
+ exit ( 1 );
+ }
+ if ( ! bfd_set_section_contents ( obfd->bfd, section,
+ buf, 0, size ) ) {
+ bfd_perror ( "Cannot set .reloc section contents" );
+ exit ( 1 );
+ }
+
+ /* Update symbols pertaining to the relocation directory */
+ for ( sym = obfd->symtab ; *sym ; sym++ ) {
+ if ( strcmp ( (*sym)->name, "_reloc_memsz" ) == 0 ) {
+ (*sym)->value = size;
+ } else if ( strcmp ( (*sym)->name, "_reloc_filesz" ) == 0 ){
+ (*sym)->value = raw_size;
+ } else if ( strcmp ( (*sym)->name, "_filesz" ) == 0 ) {
+ (*sym)->value += ( size - old_size );
+ }
+ }
+}
+
+int main ( int argc, const char *argv[] ) {
+ const char *iname;
+ const char *oname;
+ struct bfd_file *ibfd;
+ struct bfd_file *obfd;
+ asection *section;
+ arelent **reltab;
+ arelent **rel;
+ struct pe_relocs *pe_reltab = NULL;
+ asection *reloc_section;
+
+ /* Initialise libbfd */
+ bfd_init();
+
+ /* Identify intput and output files */
+ if ( argc != 3 ) {
+ fprintf ( stderr, "Syntax: %s infile outfile\n", argv[0] );
+ exit ( 1 );
+ }
+ iname = argv[1];
+ oname = argv[2];
+
+ /* Open BFD files */
+ ibfd = open_input_bfd ( iname );
+ obfd = open_output_bfd ( oname, ibfd );
+
+ /* Process relocations in all sections */
+ for ( section = ibfd->bfd->sections ; section ;
+ section = section->next ) {
+ reltab = read_reltab ( ibfd, section );
+ for ( rel = reltab ; *rel ; rel++ ) {
+ process_reloc ( section, *rel, &pe_reltab );
+ }
+ free ( reltab );
+ }
+
+ /* Create modified .reloc section */
+ reloc_section = bfd_get_section_by_name ( obfd->bfd, ".reloc" );
+ if ( ! reloc_section ) {
+ fprintf ( stderr, "Cannot find .reloc section\n" );
+ exit ( 1 );
+ }
+ create_reloc_section ( obfd, reloc_section, pe_reltab );
+
+ /* Copy other section contents */
+ for ( section = ibfd->bfd->sections ; section ;
+ section = section->next ) {
+ if ( section->output_section != reloc_section )
+ copy_bfd_section ( obfd, ibfd, section );
+ }
+
+ /* Write out files and clean up */
+ bfd_close ( obfd->bfd );
+ bfd_close ( ibfd->bfd );
+
+ return 0;
+}
diff --git a/gpxe/src/util/geniso b/gpxe/src/util/geniso
index 7642ed36..d7ddbd2b 100755
--- a/gpxe/src/util/geniso
+++ b/gpxe/src/util/geniso
@@ -52,5 +52,5 @@ do
echo "" KERNEL $g
cp -p $f $dir/$g
done >> $cfg
-mkisofs -l -o $out -c boot.cat -b isolinux.bin -no-emul-boot -boot-load-size 4 -boot-info-table $dir
+mkisofs -q -l -o $out -c boot.cat -b isolinux.bin -no-emul-boot -boot-load-size 4 -boot-info-table $dir
rm -fr $dir
diff --git a/gpxe/src/util/mergerom.pl b/gpxe/src/util/mergerom.pl
index f9c52502..f9c52502 100644..100755
--- a/gpxe/src/util/mergerom.pl
+++ b/gpxe/src/util/mergerom.pl
diff --git a/gpxe/src/util/mkconfig.pl b/gpxe/src/util/mkconfig.pl
deleted file mode 100755
index e55c2ca8..00000000
--- a/gpxe/src/util/mkconfig.pl
+++ /dev/null
@@ -1,205 +0,0 @@
-#!/usr/bin/perl -w
-
-use File::Spec::Functions qw ( :ALL );
-use File::stat;
-use strict;
-use warnings;
-
-my $cfgdir = "config";
-my $config_h = shift || "config.h";
-my @input_files;
-
-# Read in a whole file
-#
-sub read_file {
- my $file = shift;
-
- open my $fh, "<$file" or die "Could not open file $file: $!\n";
- local $/;
- my $data = <$fh>;
- close $fh;
- return $data;
-}
-
-# Write out a whole file
-#
-sub write_file {
- my $file = shift;
- my $data = shift;
-
- open my $fh, ">$file" or die "Could not write $file: $!\n";
- print $fh $data;
- close $fh;
-}
-
-# Delete a file
-#
-sub delete_file {
- my $file = shift;
-
- unlink $file or die "Could not delete $file: $!\n";
-}
-
-# Get a file modification time
-#
-sub file_mtime {
- my $file = shift;
-
- my $stat = stat ( $file ) or die "Could not stat $file: $!\n";
- return $stat->mtime;
-}
-
-# Read all the .h files in a directory
-#
-sub read_dir {
- my $dir = shift;
-
- opendir my $dh, $dir or die "Could not open directory $dir: $!\n";
- my @entries = grep { /\.h$/ } readdir $dh;
- closedir $dh;
- return @entries;
-}
-
-# Get the current configuration by reading the configuration file
-# fragments
-#
-sub current_config {
- my $dir = shift;
-
- my $cfg = {};
- foreach my $file ( read_dir ( $dir ) ) {
- $cfg->{$file} = read_file ( catfile ( $dir, $file ) );
- }
- return $cfg;
-}
-
-# Calculate guard name for a header file
-#
-sub guard {
- my $name = shift;
-
- $name =~ s/\W/_/g;
- return "CONFIG_".( uc $name );
-}
-
-# Calculate preamble for a header file
-#
-sub preamble {
- my $name = shift;
- my $master = shift;
-
- my $guard = guard ( $name );
- my $preamble = <<"EOF";
-/*
- * This file is automatically generated from $master. Do not edit this
- * file; edit $master instead.
- *
- */
-
-#ifndef $guard
-#define $guard
-EOF
- return $preamble;
-}
-
-# Calculate postamble for a header file
-#
-sub postamble {
- my $name = shift;
-
- my $guard = guard ( $name );
- return "\n#endif /* $guard */\n";
-}
-
-# Parse one config.h file into an existing configuration
-#
-sub parse_config {
- my $file = shift;
- my $cfg = shift;
- my $cursor = "";
-
- push ( @input_files, $file );
-
- open my $fh, "<$file" or die "Could not open $file: $!\n";
- while ( <$fh> ) {
- if ( ( my $newcursor, my $suffix ) = /\@BEGIN\s+(\w+\.h)(.*)$/ ) {
- die "Missing \"\@END $cursor\" before \"\@BEGIN $1\""
- ." at $file line $.\n" if $cursor;
- $cursor = $newcursor;
- $cfg->{$cursor} = preamble ( $cursor, $file )
- unless exists $cfg->{$cursor};
- $cfg->{$cursor} .= "\n/*".$suffix."\n";
- } elsif ( ( my $prefix, my $oldcursor ) = /^(.*)\@END\s+(\w+\.h)/ ) {
- die "Missing \"\@BEGIN $oldcursor\" before \"\@END $oldcursor\""
- ." at $file line $.\n" unless $cursor eq $oldcursor;
- $cfg->{$cursor} .= $prefix."*/\n";
- $cursor = "";
- } elsif ( ( my $newfile ) = /\@TRYSOURCE\s+([\w\-]+\.h)/ ) {
- die "Missing \"\@END $cursor\" before \"\@TRYSOURCE $newfile\""
- ." at $file line $.\n" if $cursor;
- parse_config ( $newfile, $cfg ) if -e $newfile;
- } else {
- $cfg->{$cursor} .= $_ if $cursor;
- }
- }
- close $fh;
- die "Missing \"\@END $cursor\" in $file\n" if $cursor;
-}
-
-# Get the new configuration by splitting config.h file using the
-# @BEGIN/@END tags
-#
-sub new_config {
- my $file = shift;
- my $cfg = {};
-
- parse_config ( $file, $cfg );
-
- foreach my $cursor ( keys %$cfg ) {
- $cfg->{$cursor} .= postamble ( $cursor );
- }
-
- return $cfg;
-}
-
-#############################################################################
-#
-# Main program
-
-# Read in current config file fragments
-#
-my $current = current_config ( $cfgdir );
-
-# Read in config.h and split it into fragments
-#
-my $new = new_config ( $config_h );
-
-# Delete any no-longer-wanted config file fragments
-#
-foreach my $file ( keys %$current ) {
- unlink catfile ( $cfgdir, $file ) unless exists $new->{$file};
-}
-
-# Write out any modified fragments, and find the oldest timestamp of
-# any unmodified fragments.
-#
-my $oldest = time ();
-foreach my $file ( keys %$new ) {
- if ( $current->{$file} && $new->{$file} eq $current->{$file} ) {
- # Unmodified
- my $time = file_mtime ( catfile ( $cfgdir, $file ) );
- $oldest = $time if $time < $oldest;
- } else {
- write_file ( catfile ( $cfgdir, $file ), $new->{$file} );
- }
-}
-
-# If we now have fragments that are older than config.h, set the
-# timestamp on each input file to match the oldest fragment, to
-# prevent make from always attempting to rebuild the fragments.
-#
-foreach my $file ( @input_files ) {
- if ( $oldest < file_mtime ( $file ) ) {
- utime time(), $oldest, $file or die "Could not touch $file: $!\n";
- }
-}
diff --git a/gpxe/src/util/sortobjdump.pl b/gpxe/src/util/sortobjdump.pl
index 8ad7314b..1373a7ff 100755
--- a/gpxe/src/util/sortobjdump.pl
+++ b/gpxe/src/util/sortobjdump.pl
@@ -8,7 +8,7 @@ use warnings;
# linker maps produced by "make bin/%.map" by also showing the values
# of all non-global symbols.
-my %section_idx = ( "*ABS*" => "." );
+my %section_idx = ( "*ABS*" => ".", "*UND*" => "_" );
my %lines;
while ( <> ) {
if ( /^\s+(\d+)\s+([\.\*]\S+)\s+[0-9a-fA-F]+\s+[0-9a-fA-F]/ ) {
diff --git a/gpxe/src/util/zbin.c b/gpxe/src/util/zbin.c
index b24f401e..c1082b31 100644
--- a/gpxe/src/util/zbin.c
+++ b/gpxe/src/util/zbin.c
@@ -6,6 +6,8 @@
#include "nrv2b.c"
FILE *infile, *outfile;
+#define DEBUG 0
+
struct input_file {
void *buf;
size_t len;
@@ -151,6 +153,11 @@ static int process_zinfo_copy ( struct input_file *input,
return -1;
}
+ if ( DEBUG ) {
+ fprintf ( stderr, "COPY [%#zx,%#zx) to [%#zx,%#zx)\n", offset, ( offset + len ),
+ output->len, ( output->len + len ) );
+ }
+
memcpy ( ( output->buf + output->len ),
( input->buf + offset ), len );
output->len += len;
@@ -184,6 +191,11 @@ static int process_zinfo_pack ( struct input_file *input,
return -1;
}
+ if ( DEBUG ) {
+ fprintf ( stderr, "PACK [%#zx,%#zx) to [%#zx,%#zx)\n", offset, ( offset + len ),
+ output->len, ( output->len + packed_len ) );
+ }
+
output->len += packed_len;
if ( output->len > output->max_len ) {
fprintf ( stderr, "Output buffer overrun on pack\n" );
@@ -200,6 +212,8 @@ static int process_zinfo_subtract ( struct input_file *input,
size_t offset = subtract->offset;
void *target;
long delta;
+ unsigned long old;
+ unsigned long new;
if ( ( offset + datasize ) > output->len ) {
fprintf ( stderr, "Subtract at %#zx outside output buffer\n",
@@ -214,21 +228,34 @@ static int process_zinfo_subtract ( struct input_file *input,
switch ( datasize ) {
case 1: {
uint8_t *byte = target;
+ old = *byte;
*byte += delta;
+ new = *byte;
break; }
case 2: {
uint16_t *word = target;
+ old = *word;
*word += delta;
+ new = *word;
break; }
case 4: {
uint32_t *dword = target;
+ old = *dword;
*dword += delta;
+ new = *dword;
break; }
default:
fprintf ( stderr, "Unsupported subtract datasize %d\n",
datasize );
return -1;
}
+
+ if ( DEBUG ) {
+ fprintf ( stderr, "SUBx [%#zx,%#zx) (%#lx+(%#lx/%#lx)-(%#lx/%#lx)) = %#lx\n",
+ offset, ( offset + datasize ), old, output->len, subtract->divisor,
+ input->len, subtract->divisor, new );
+ }
+
return 0;
}